classiq 0.51.1__py3-none-any.whl → 0.53.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 (158) hide show
  1. classiq/_internals/api_wrapper.py +47 -15
  2. classiq/_internals/authentication/auth0.py +20 -4
  3. classiq/_internals/authentication/password_manager.py +16 -4
  4. classiq/_internals/client.py +3 -3
  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 +25 -6
  12. classiq/execution/__init__.py +5 -0
  13. classiq/execution/execution_session.py +43 -2
  14. classiq/execution/iqcc.py +63 -0
  15. classiq/execution/jobs.py +2 -2
  16. classiq/execution/qaoa.py +84 -0
  17. classiq/executor.py +3 -3
  18. classiq/interface/_version.py +1 -1
  19. classiq/interface/analyzer/analysis_params.py +19 -9
  20. classiq/interface/analyzer/cytoscape_graph.py +10 -3
  21. classiq/interface/analyzer/result.py +6 -5
  22. classiq/interface/applications/qsvm.py +13 -12
  23. classiq/interface/backend/backend_preferences.py +78 -105
  24. classiq/interface/backend/ionq/ionq_quantum_program.py +12 -19
  25. classiq/interface/backend/pydantic_backend.py +24 -12
  26. classiq/interface/backend/quantum_backend_providers.py +2 -0
  27. classiq/interface/chemistry/fermionic_operator.py +7 -7
  28. classiq/interface/chemistry/ground_state_problem.py +23 -18
  29. classiq/interface/chemistry/molecule.py +10 -5
  30. classiq/interface/chemistry/operator.py +71 -44
  31. classiq/interface/combinatorial_optimization/mht_qaoa_input.py +2 -1
  32. classiq/interface/debug_info/debug_info.py +3 -4
  33. classiq/interface/exceptions.py +3 -1
  34. classiq/interface/execution/iqcc.py +19 -0
  35. classiq/interface/execution/jobs.py +10 -10
  36. classiq/interface/executor/aws_execution_cost.py +37 -20
  37. classiq/interface/executor/execution_preferences.py +1 -2
  38. classiq/interface/executor/execution_request.py +2 -2
  39. classiq/interface/executor/execution_result.py +4 -2
  40. classiq/interface/executor/iqae_result.py +1 -1
  41. classiq/interface/executor/optimizer_preferences.py +14 -10
  42. classiq/interface/executor/quantum_code.py +21 -16
  43. classiq/interface/executor/register_initialization.py +10 -10
  44. classiq/interface/executor/result.py +31 -17
  45. classiq/interface/executor/vqe_result.py +1 -1
  46. classiq/interface/finance/function_input.py +27 -18
  47. classiq/interface/finance/log_normal_model_input.py +2 -2
  48. classiq/interface/finance/model_input.py +3 -2
  49. classiq/interface/generator/amplitude_loading.py +8 -6
  50. classiq/interface/generator/arith/argument_utils.py +24 -0
  51. classiq/interface/generator/arith/arithmetic.py +5 -3
  52. classiq/interface/generator/arith/arithmetic_expression_abc.py +36 -14
  53. classiq/interface/generator/arith/arithmetic_operations.py +6 -3
  54. classiq/interface/generator/arith/binary_ops.py +88 -63
  55. classiq/interface/generator/arith/extremum_operations.py +22 -13
  56. classiq/interface/generator/arith/logical_ops.py +6 -4
  57. classiq/interface/generator/arith/number_utils.py +3 -3
  58. classiq/interface/generator/arith/register_user_input.py +32 -17
  59. classiq/interface/generator/arith/unary_ops.py +5 -4
  60. classiq/interface/generator/chemistry_function_params.py +2 -1
  61. classiq/interface/generator/circuit_code/circuit_code.py +2 -1
  62. classiq/interface/generator/commuting_pauli_exponentiation.py +6 -5
  63. classiq/interface/generator/complex_type.py +14 -18
  64. classiq/interface/generator/control_state.py +32 -26
  65. classiq/interface/generator/expressions/expression.py +6 -5
  66. classiq/interface/generator/function_params.py +22 -39
  67. classiq/interface/generator/functions/classical_function_declaration.py +1 -1
  68. classiq/interface/generator/functions/classical_type.py +32 -23
  69. classiq/interface/generator/functions/concrete_types.py +8 -7
  70. classiq/interface/generator/functions/function_declaration.py +4 -5
  71. classiq/interface/generator/functions/type_name.py +5 -4
  72. classiq/interface/generator/generated_circuit_data.py +9 -6
  73. classiq/interface/generator/grover_diffuser.py +26 -18
  74. classiq/interface/generator/grover_operator.py +32 -22
  75. classiq/interface/generator/hamiltonian_evolution/exponentiation.py +3 -4
  76. classiq/interface/generator/hamiltonian_evolution/qdrift.py +4 -4
  77. classiq/interface/generator/hamiltonian_evolution/suzuki_trotter.py +8 -7
  78. classiq/interface/generator/hardware/hardware_data.py +27 -26
  79. classiq/interface/generator/hardware_efficient_ansatz.py +11 -6
  80. classiq/interface/generator/hartree_fock.py +2 -1
  81. classiq/interface/generator/identity.py +7 -2
  82. classiq/interface/generator/linear_pauli_rotations.py +27 -14
  83. classiq/interface/generator/mcu.py +15 -12
  84. classiq/interface/generator/mcx.py +18 -10
  85. classiq/interface/generator/model/constraints.py +4 -2
  86. classiq/interface/generator/model/model.py +2 -1
  87. classiq/interface/generator/model/preferences/preferences.py +30 -32
  88. classiq/interface/generator/oracles/custom_oracle.py +13 -10
  89. classiq/interface/generator/piecewise_linear_amplitude_loading.py +37 -21
  90. classiq/interface/generator/qpe.py +38 -26
  91. classiq/interface/generator/qsvm.py +4 -4
  92. classiq/interface/generator/quantum_function_call.py +57 -44
  93. classiq/interface/generator/quantum_program.py +8 -6
  94. classiq/interface/generator/range_types.py +10 -11
  95. classiq/interface/generator/standard_gates/controlled_standard_gates.py +9 -5
  96. classiq/interface/generator/standard_gates/standard_angle_metaclass.py +2 -6
  97. classiq/interface/generator/standard_gates/u_gate.py +7 -10
  98. classiq/interface/generator/state_preparation/computational_basis_state_preparation.py +2 -1
  99. classiq/interface/generator/state_preparation/distributions.py +12 -12
  100. classiq/interface/generator/state_preparation/state_preparation.py +22 -16
  101. classiq/interface/generator/types/enum_declaration.py +2 -1
  102. classiq/interface/generator/ucc.py +2 -1
  103. classiq/interface/generator/unitary_gate.py +2 -1
  104. classiq/interface/generator/user_defined_function_params.py +3 -0
  105. classiq/interface/generator/visitor.py +1 -1
  106. classiq/interface/hardware.py +18 -3
  107. classiq/interface/helpers/custom_pydantic_types.py +38 -47
  108. classiq/interface/helpers/dotdict.py +18 -0
  109. classiq/interface/helpers/pydantic_model_helpers.py +3 -2
  110. classiq/interface/helpers/versioned_model.py +1 -4
  111. classiq/interface/ide/ide_data.py +5 -5
  112. classiq/interface/ide/visual_model.py +18 -5
  113. classiq/interface/interface_version.py +1 -1
  114. classiq/interface/jobs.py +12 -22
  115. classiq/interface/model/bind_operation.py +2 -1
  116. classiq/interface/model/classical_parameter_declaration.py +10 -4
  117. classiq/interface/model/handle_binding.py +20 -24
  118. classiq/interface/model/inplace_binary_operation.py +16 -9
  119. classiq/interface/model/model.py +21 -11
  120. classiq/interface/model/native_function_definition.py +10 -0
  121. classiq/interface/model/port_declaration.py +10 -7
  122. classiq/interface/model/quantum_expressions/arithmetic_operation.py +6 -4
  123. classiq/interface/model/quantum_function_declaration.py +22 -11
  124. classiq/interface/model/quantum_statement.py +6 -7
  125. classiq/interface/model/quantum_type.py +22 -19
  126. classiq/interface/model/statement_block.py +9 -9
  127. classiq/interface/server/global_versions.py +4 -5
  128. classiq/interface/server/routes.py +8 -0
  129. classiq/model_expansions/evaluators/parameter_types.py +3 -3
  130. classiq/model_expansions/expression_renamer.py +1 -1
  131. classiq/model_expansions/quantum_operations/control.py +11 -12
  132. classiq/model_expansions/quantum_operations/emitter.py +22 -0
  133. classiq/model_expansions/quantum_operations/expression_operation.py +2 -20
  134. classiq/model_expansions/quantum_operations/inplace_binary_operation.py +42 -12
  135. classiq/model_expansions/quantum_operations/invert.py +1 -1
  136. classiq/model_expansions/quantum_operations/phase.py +4 -5
  137. classiq/model_expansions/quantum_operations/power.py +1 -1
  138. classiq/model_expansions/quantum_operations/quantum_assignment_operation.py +50 -9
  139. classiq/model_expansions/quantum_operations/variable_decleration.py +2 -2
  140. classiq/model_expansions/quantum_operations/within_apply.py +1 -1
  141. classiq/qmod/__init__.py +2 -0
  142. classiq/qmod/builtins/__init__.py +1 -3
  143. classiq/qmod/builtins/functions/__init__.py +9 -0
  144. classiq/qmod/builtins/functions/arithmetic.py +10 -0
  145. classiq/qmod/builtins/functions/standard_gates.py +14 -14
  146. classiq/qmod/builtins/functions/variational.py +37 -0
  147. classiq/qmod/create_model_function.py +16 -6
  148. classiq/qmod/qmod_parameter.py +3 -1
  149. classiq/qmod/quantum_expandable.py +43 -10
  150. classiq/qmod/quantum_function.py +24 -2
  151. classiq/qmod/semantics/static_semantics_visitor.py +3 -1
  152. classiq/qmod/synthesize_separately.py +16 -0
  153. classiq/qmod/type_attribute_remover.py +1 -1
  154. classiq/qmod/write_qmod.py +2 -4
  155. classiq/synthesis.py +11 -13
  156. {classiq-0.51.1.dist-info → classiq-0.53.0.dist-info}/METADATA +3 -2
  157. {classiq-0.51.1.dist-info → classiq-0.53.0.dist-info}/RECORD +158 -152
  158. {classiq-0.51.1.dist-info → classiq-0.53.0.dist-info}/WHEEL +0 -0
@@ -1,11 +1,12 @@
1
- from typing import TYPE_CHECKING, Any, Dict, List, Optional, Union
1
+ from typing import TYPE_CHECKING, Any, Dict, List, Optional, Sequence, Union
2
2
 
3
3
  import pydantic
4
- from typing_extensions import TypeAlias
4
+ from pydantic import Field
5
+ from pydantic_core.core_schema import ValidationInfo
6
+ from typing_extensions import Annotated, Self, TypeAlias
5
7
 
6
8
  from classiq.interface.backend.backend_preferences import (
7
9
  BackendPreferences,
8
- validate_backend_service_provider,
9
10
  )
10
11
  from classiq.interface.backend.quantum_backend_providers import (
11
12
  AllBackendsNameByVendor,
@@ -27,14 +28,14 @@ from classiq.interface.helpers.custom_pydantic_types import PydanticMachinePreci
27
28
  if TYPE_CHECKING:
28
29
  VisualizationLevel: TypeAlias = Optional[int]
29
30
  else:
30
- VisualizationLevel: TypeAlias = Optional[pydantic.conint(ge=-1)]
31
+ VisualizationLevel: TypeAlias = Optional[Annotated[int, Field(ge=-1)]]
31
32
 
32
33
  if TYPE_CHECKING:
33
34
  PydanticBackendName = str
34
35
  else:
35
- PydanticBackendName = pydantic.constr(
36
- strict=True, min_length=1, regex="^([.A-Za-z0-9_-]*)$"
37
- )
36
+ PydanticBackendName = Annotated[
37
+ str, Field(strict=True, min_length=1, pattern="^([.A-Za-z0-9_-]*)$")
38
+ ]
38
39
 
39
40
 
40
41
  class QuantumFormat(StrEnum):
@@ -57,9 +58,9 @@ _SERVICE_PROVIDER_TO_FORMAT: Dict[Provider, QuantumFormat] = {
57
58
  if TYPE_CHECKING:
58
59
  PydanticConstrainedQuantumFormatList = List[QuantumFormat]
59
60
  else:
60
- PydanticConstrainedQuantumFormatList = pydantic.conlist(
61
- QuantumFormat, min_items=1, max_items=len(QuantumFormat)
62
- )
61
+ PydanticConstrainedQuantumFormatList = Annotated[
62
+ List[QuantumFormat], Field(min_length=1, max_length=len(QuantumFormat))
63
+ ]
63
64
 
64
65
 
65
66
  class TranspilationOption(StrEnum):
@@ -75,7 +76,7 @@ class TranspilationOption(StrEnum):
75
76
  return self != TranspilationOption.NONE
76
77
 
77
78
 
78
- class Preferences(pydantic.BaseModel, extra=pydantic.Extra.forbid):
79
+ class Preferences(pydantic.BaseModel, extra="forbid"):
79
80
  """
80
81
  Preferences for synthesizing a quantum circuit.
81
82
 
@@ -194,21 +195,14 @@ class Preferences(pydantic.BaseModel, extra=pydantic.Extra.forbid):
194
195
  description="The random seed used for the generation",
195
196
  )
196
197
 
197
- @pydantic.validator("backend_service_provider", pre=True)
198
- def validate_backend_service_provider(
199
- cls, backend_service_provider: Any
200
- ) -> Optional[Provider]:
201
- if backend_service_provider is None:
202
- return None
203
- return validate_backend_service_provider(backend_service_provider)
204
-
205
- @pydantic.validator("optimization_timeout_seconds")
198
+ @pydantic.field_validator("optimization_timeout_seconds", mode="before")
199
+ @classmethod
206
200
  def optimization_timeout_less_than_generation_timeout(
207
201
  cls,
208
202
  optimization_timeout_seconds: Optional[pydantic.PositiveInt],
209
- values: Dict[str, Any],
203
+ info: ValidationInfo,
210
204
  ) -> Optional[pydantic.PositiveInt]:
211
- generation_timeout_seconds = values.get("timeout_seconds")
205
+ generation_timeout_seconds = info.data.get("timeout_seconds")
212
206
  if generation_timeout_seconds is None or optimization_timeout_seconds is None:
213
207
  return optimization_timeout_seconds
214
208
  if optimization_timeout_seconds >= generation_timeout_seconds:
@@ -219,16 +213,20 @@ class Preferences(pydantic.BaseModel, extra=pydantic.Extra.forbid):
219
213
  )
220
214
  return optimization_timeout_seconds
221
215
 
222
- @pydantic.validator("output_format", pre=True)
216
+ @pydantic.field_validator("output_format", mode="before")
217
+ @classmethod
223
218
  def make_output_format_list(cls, output_format: Any) -> List:
224
- if not pydantic.utils.sequence_like(output_format):
219
+ if not isinstance(output_format, Sequence) or isinstance(output_format, str):
225
220
  output_format = [output_format]
226
221
 
227
222
  return output_format
228
223
 
229
- @pydantic.validator("output_format", always=True)
224
+ @pydantic.field_validator("output_format", mode="before")
225
+ @classmethod
230
226
  def validate_output_format(
231
- cls, output_format: PydanticConstrainedQuantumFormatList, values: Dict[str, Any]
227
+ cls,
228
+ output_format: PydanticConstrainedQuantumFormatList,
229
+ info: ValidationInfo,
232
230
  ) -> PydanticConstrainedQuantumFormatList:
233
231
  if len(output_format) != len(set(output_format)):
234
232
  raise ClassiqValueError(
@@ -236,7 +234,7 @@ class Preferences(pydantic.BaseModel, extra=pydantic.Extra.forbid):
236
234
  "has at least one format that appears twice or more"
237
235
  )
238
236
 
239
- service_provider = values.get("backend_service_provider")
237
+ service_provider = info.data.get("backend_service_provider")
240
238
  if service_provider is None:
241
239
  return output_format
242
240
 
@@ -246,13 +244,13 @@ class Preferences(pydantic.BaseModel, extra=pydantic.Extra.forbid):
246
244
 
247
245
  return output_format
248
246
 
249
- @pydantic.root_validator()
250
- def validate_backend(cls, values: Dict[str, Any]) -> Dict[str, Any]:
251
- backend_name = values.get("backend_name")
252
- backend_service_provider = values.get("backend_service_provider")
247
+ @pydantic.model_validator(mode="after")
248
+ def validate_backend(self) -> Self:
249
+ backend_name = self.backend_name
250
+ backend_service_provider = self.backend_service_provider
253
251
  if (backend_name is None) != (backend_service_provider is None):
254
252
  raise ClassiqValueError(BACKEND_VALIDATION_ERROR_MESSAGE)
255
- return values
253
+ return self
256
254
 
257
255
  @property
258
256
  def backend_preferences(self) -> Optional[BackendPreferences]:
@@ -22,18 +22,21 @@ class CustomOracle(OracleABC[QubitState]):
22
22
  default_factory=CustomFunction,
23
23
  )
24
24
 
25
- @pydantic.root_validator(pre=True)
26
- def _parse_oracle(cls, values: Dict[str, Any]) -> Dict[str, Any]:
27
- parse_function_params_values(
28
- values=values,
29
- params_key="custom_oracle_params",
30
- discriminator_key="custom_oracle",
31
- param_classes={CustomFunction},
32
- default_parser_class=CustomFunction,
33
- )
25
+ @pydantic.model_validator(mode="before")
26
+ @classmethod
27
+ def _parse_oracle(cls, values: Any) -> Dict[str, Any]:
28
+ if isinstance(values, dict):
29
+ parse_function_params_values(
30
+ values=values,
31
+ params_key="custom_oracle_params",
32
+ discriminator_key="custom_oracle",
33
+ param_classes={CustomFunction},
34
+ default_parser_class=CustomFunction,
35
+ )
34
36
  return values
35
37
 
36
- @pydantic.validator("custom_oracle_params")
38
+ @pydantic.field_validator("custom_oracle_params")
39
+ @classmethod
37
40
  def _validate_names_match_oracle(
38
41
  cls, custom_oracle_params: CustomFunction
39
42
  ) -> CustomFunction:
@@ -2,6 +2,8 @@ import math
2
2
  from typing import Any, Dict, Generic, List, Sequence, Tuple, TypeVar
3
3
 
4
4
  import pydantic
5
+ from pydantic import BaseModel, ConfigDict, Field, field_validator
6
+ from pydantic_core.core_schema import ValidationInfo
5
7
 
6
8
  from classiq.interface.exceptions import ClassiqError
7
9
  from classiq.interface.generator.arith.register_user_input import RegisterArithmeticInfo
@@ -18,8 +20,8 @@ Breakpoint = TypeVar("Breakpoint")
18
20
 
19
21
 
20
22
  class AffineMap(HashablePydanticBaseModel):
21
- slope: float = pydantic.Field(default=1.0)
22
- offset: float = pydantic.Field(default=0.0)
23
+ slope: float = Field(default=1.0)
24
+ offset: float = Field(default=0.0)
23
25
 
24
26
  def evaluate(self, x: float) -> float:
25
27
  return self.offset + self.slope * x
@@ -27,16 +29,15 @@ class AffineMap(HashablePydanticBaseModel):
27
29
  def image_bounds(self, domain_bounds: Tuple[float, float]) -> Tuple[float, float]:
28
30
  return self.evaluate(domain_bounds[0]), self.evaluate(domain_bounds[1])
29
31
 
30
- class Config:
31
- frozen = True
32
+ model_config = ConfigDict(frozen=True)
32
33
 
33
34
 
34
35
  class PiecewiseLinearAmplitudeLoadingABC(
35
- FunctionParams, pydantic.generics.GenericModel, Generic[Breakpoint]
36
+ FunctionParams, BaseModel, Generic[Breakpoint]
36
37
  ):
37
- num_qubits: pydantic.PositiveInt = pydantic.Field()
38
- breakpoints: Sequence[pydantic.NonNegativeInt] = pydantic.Field()
39
- affine_maps: Sequence[AffineMap] = pydantic.Field()
38
+ num_qubits: int = Field()
39
+ breakpoints: Sequence[int] = Field()
40
+ affine_maps: Sequence[AffineMap] = Field()
40
41
 
41
42
  def _create_ios(self) -> None:
42
43
  self._inputs = {
@@ -58,19 +59,35 @@ class PiecewiseLinearAmplitudeLoadingABC(
58
59
  top = max(max(piece) for piece in piece_bounds)
59
60
  return bottom, top
60
61
 
61
- @pydantic.validator("breakpoints")
62
+ @field_validator("breakpoints", mode="before")
63
+ @classmethod
62
64
  def _validate_breakpoints(cls, breakpoints: Sequence[int]) -> Sequence[int]:
65
+ return cls.validate_breakpoints(breakpoints)
66
+
67
+ @classmethod
68
+ def validate_breakpoints(cls, breakpoints: Sequence[int]) -> Sequence[int]:
63
69
  assert len(breakpoints) == len(
64
70
  set(breakpoints)
65
71
  ), "Repeated breakpoints encountered"
66
72
  assert list(breakpoints) == sorted(breakpoints), "Breakpoints not sorted"
67
- return breakpoints
73
+ return list(map(int, breakpoints))
68
74
 
69
- @pydantic.root_validator(pre=True)
70
- def _validate_lengths(cls, values: Dict[str, Any]) -> Dict[str, Any]:
75
+ @pydantic.model_validator(mode="before")
76
+ @classmethod
77
+ def _validate_lengths(cls, values: Any) -> Dict[str, Any]:
71
78
  breakpoints = values.get("breakpoints", list())
72
79
  affine_maps = values.get("affine_maps", list())
73
80
  num_qubits = values.get("num_qubits", int)
81
+ if isinstance(values, dict):
82
+ breakpoints = values.get("breakpoints", list())
83
+ affine_maps = values.get("affine_maps", list())
84
+ num_qubits = values.get("num_qubits", int)
85
+ elif isinstance(values, PiecewiseLinearAmplitudeLoadingABC):
86
+ breakpoints = values.breakpoints
87
+ affine_maps = values.affine_maps
88
+ num_qubits = values.num_qubits
89
+ values = values.__dict__
90
+
74
91
  assert len(breakpoints) - 1 == len(
75
92
  affine_maps
76
93
  ), "Size mismatch between the number of slopes and breakpoints. The number of breakpoints should be the number of slopes + 1"
@@ -80,28 +97,27 @@ class PiecewiseLinearAmplitudeLoadingABC(
80
97
  return values
81
98
 
82
99
 
83
- class PiecewiseLinearRotationAmplitudeLoading(
84
- PiecewiseLinearAmplitudeLoadingABC[pydantic.NonNegativeInt]
85
- ):
100
+ class PiecewiseLinearRotationAmplitudeLoading(PiecewiseLinearAmplitudeLoadingABC[int]):
86
101
  pass
87
102
 
88
- @pydantic.validator("breakpoints")
89
- def _validate_breakpoints(
90
- cls, breakpoints: Sequence[int], values: Dict[str, Any]
103
+ @field_validator("breakpoints")
104
+ @classmethod
105
+ def _validate_breakpoints_field(
106
+ cls, breakpoints: Sequence[int], info: ValidationInfo
91
107
  ) -> Sequence[int]:
92
- num_qubits = values.get("num_qubits")
108
+ num_qubits = info.data.get("num_qubits")
93
109
  assert isinstance(num_qubits, int), "Must have an integer number of qubits"
94
110
  assert min(breakpoints) == 0, "First breakpoint must be 0"
95
111
  assert (
96
112
  max(breakpoints) == 2**num_qubits - 1
97
113
  ), f"Last breakpoint must be {2**num_qubits - 1}"
98
- return PiecewiseLinearAmplitudeLoadingABC._validate_breakpoints(
114
+ return PiecewiseLinearAmplitudeLoadingABC.validate_breakpoints(
99
115
  breakpoints=breakpoints
100
116
  )
101
117
 
102
118
 
103
119
  class PiecewiseLinearAmplitudeLoading(PiecewiseLinearAmplitudeLoadingABC[float]):
104
- rescaling_factor: float = pydantic.Field(default=0.25 * math.pi)
120
+ rescaling_factor: float = Field(default=0.25 * math.pi)
105
121
 
106
122
  def rescaled(self) -> PiecewiseLinearRotationAmplitudeLoading:
107
123
  c, d = self._get_image_bounds()
@@ -1,6 +1,9 @@
1
1
  from typing import Any, Dict, Optional, Tuple
2
2
 
3
3
  import pydantic
4
+ from pydantic import ConfigDict
5
+ from pydantic_core.core_schema import ValidationInfo
6
+ from typing_extensions import Self
4
7
 
5
8
  from classiq.interface.exceptions import ClassiqMismatchIOsError, ClassiqValueError
6
9
  from classiq.interface.generator.arith.register_user_input import RegisterArithmeticInfo
@@ -36,9 +39,7 @@ class ExponentiationScaling(pydantic.BaseModel):
36
39
  default=2.0,
37
40
  description="The scaling factor of the exponentiation max_depth; defaults to 2.",
38
41
  )
39
-
40
- class Config:
41
- frozen = True
42
+ model_config = ConfigDict(frozen=True)
42
43
 
43
44
 
44
45
  class ExponentiationSpecification(pydantic.BaseModel):
@@ -55,17 +56,13 @@ class ExponentiationSpecification(pydantic.BaseModel):
55
56
  default=None,
56
57
  description="The max_depth of each exponentiation function; overrides scaling.",
57
58
  )
59
+ model_config = ConfigDict(frozen=True)
58
60
 
59
- class Config:
60
- frozen = True
61
-
62
- @pydantic.root_validator
63
- def _validate_exponentiation_specification(
64
- cls, values: Dict[str, Any]
65
- ) -> Dict[str, Any]:
66
- if values.get("scaling") is None and values.get("max_depths") is None:
61
+ @pydantic.model_validator(mode="after")
62
+ def _validate_exponentiation_specification(self) -> Self:
63
+ if self.scaling is None and self.max_depths is None:
67
64
  raise ClassiqValueError("At least one specification must be provided.")
68
- return values
65
+ return self
69
66
 
70
67
 
71
68
  class PhaseEstimation(FunctionParams):
@@ -104,28 +101,42 @@ class PhaseEstimation(FunctionParams):
104
101
  self._outputs[self._output_name] = RegisterArithmeticInfo(size=self.size)
105
102
  self._create_zero_input_registers({DEFAULT_ZERO_NAME: self.size})
106
103
 
107
- @pydantic.root_validator(pre=True)
108
- def _validate_composite_name(cls, values: Dict[str, Any]) -> Dict[str, Any]:
109
- if isinstance(values.get("unitary_params"), CustomFunction) and not values.get(
110
- "unitary"
111
- ):
104
+ @pydantic.model_validator(mode="before")
105
+ @classmethod
106
+ def _validate_composite_name(cls, values: Any) -> Dict[str, Any]:
107
+ if not isinstance(values, dict):
108
+ return values
109
+ unitary_params = values.get("unitary_params")
110
+ unitary = values.get("unitary")
111
+
112
+ if isinstance(unitary_params, CustomFunction) and not unitary:
112
113
  raise ClassiqValueError(
113
114
  "`PhaseEstimation` of a user define function (`CustomFunction`) must receive the function name from the `unitary` field"
114
115
  )
115
116
  return values
116
117
 
117
- @pydantic.root_validator(pre=True)
118
- def _parse_function_params(cls, values: Dict[str, Any]) -> Dict[str, Any]:
118
+ @pydantic.model_validator(mode="before")
119
+ @classmethod
120
+ def _parse_function_params(
121
+ cls, values: Any, info: ValidationInfo
122
+ ) -> Dict[str, Any]:
123
+ vals = info.data.copy() if info.data else {}
124
+ if isinstance(values, dict):
125
+ vals = values
126
+ elif isinstance(values, PhaseEstimation):
127
+ vals = values.model_dump()
128
+
119
129
  parse_function_params_values(
120
- values=values,
130
+ values=vals,
121
131
  params_key="unitary_params",
122
132
  discriminator_key="unitary",
123
133
  param_classes=function_param_library_without_self_reference.param_list,
124
134
  default_parser_class=CustomFunction,
125
135
  )
126
- return values
136
+ return vals
127
137
 
128
- @pydantic.validator("unitary_params")
138
+ @pydantic.field_validator("unitary_params")
139
+ @classmethod
129
140
  def _validate_unitary_params(cls, unitary_params: FunctionParams) -> FunctionParams:
130
141
  if not unitary_params.is_powerable():
131
142
  if isinstance(unitary_params, CustomFunction):
@@ -135,22 +146,23 @@ class PhaseEstimation(FunctionParams):
135
146
  )
136
147
  return unitary_params
137
148
 
138
- @pydantic.validator("exponentiation_specification")
149
+ @pydantic.field_validator("exponentiation_specification")
150
+ @classmethod
139
151
  def _validate_exponentiation_specification(
140
152
  cls,
141
153
  exponentiation_specification: Optional[ExponentiationSpecification],
142
- values: Dict[str, Any],
154
+ validation_info: ValidationInfo,
143
155
  ) -> Optional[ExponentiationSpecification]:
144
156
  if exponentiation_specification is None:
145
157
  return exponentiation_specification
146
- unitary_params = values.get("unitary_params")
158
+ unitary_params = validation_info.data.get("unitary_params")
147
159
  if not isinstance(unitary_params, Exponentiation):
148
160
  raise ClassiqValueError(
149
161
  "exponentiation_specification is only valid for Exponentiation unitary_params."
150
162
  )
151
163
  if exponentiation_specification.max_depths is not None and len(
152
164
  exponentiation_specification.max_depths
153
- ) != values.get("size"):
165
+ ) != validation_info.data.get("size"):
154
166
  raise ClassiqValueError(
155
167
  "Length of max_depths must match the provided size."
156
168
  )
@@ -2,6 +2,7 @@ from typing import List, Literal, Optional, Union
2
2
 
3
3
  import numpy as np
4
4
  import pydantic
5
+ from pydantic import ConfigDict
5
6
 
6
7
  from classiq.interface.enum_utils import StrEnum
7
8
  from classiq.interface.exceptions import ClassiqQSVMError, ClassiqValueError
@@ -28,9 +29,7 @@ class QSVMFeatureMapEntanglement(StrEnum):
28
29
 
29
30
  class QSVMFeatureMapDimensional(HashablePydanticBaseModel):
30
31
  feature_dimension: Optional[int] = None
31
-
32
- class Config:
33
- frozen = True
32
+ model_config = ConfigDict(frozen=True)
34
33
 
35
34
 
36
35
  class QSVMFeatureMapPauli(QSVMFeatureMapDimensional):
@@ -42,7 +41,8 @@ class QSVMFeatureMapPauli(QSVMFeatureMapDimensional):
42
41
  parameter_prefix: str = "x"
43
42
  name: str = "PauliFeatureMap"
44
43
 
45
- @pydantic.validator("paulis", pre=True)
44
+ @pydantic.field_validator("paulis", mode="before")
45
+ @classmethod
46
46
  def set_paulis(cls, paulis: List[str]) -> List[str]:
47
47
  # iterate every letter in every string in the list of paulis
48
48
  for s in paulis:
@@ -21,7 +21,8 @@ from typing import (
21
21
  from uuid import UUID, uuid4
22
22
 
23
23
  import pydantic
24
- from pydantic import BaseModel, Extra
24
+ from pydantic import BaseModel, ConfigDict
25
+ from pydantic_core.core_schema import ValidationInfo
25
26
 
26
27
  from classiq.interface.exceptions import ClassiqControlError, ClassiqValueError
27
28
  from classiq.interface.generator import function_param_list, function_params as f_params
@@ -146,10 +147,11 @@ class SynthesisQuantumFunctionCall(BaseModel):
146
147
  )
147
148
  name: PydanticNonEmptyString = pydantic.Field(
148
149
  default=None,
150
+ validate_default=True,
149
151
  description="The name of the function instance. "
150
152
  "If not set, determined automatically.",
151
153
  )
152
- model_source_id: Optional[UUID] = pydantic.Field(default=None)
154
+ source_id: Optional[UUID] = pydantic.Field(default=None)
153
155
  arithmetic_id: Optional[str] = pydantic.Field(default=None)
154
156
  inverse_op_id: Optional[UUID] = pydantic.Field(default=None)
155
157
 
@@ -214,8 +216,9 @@ class SynthesisQuantumFunctionCall(BaseModel):
214
216
  return self.function_params.inputs_full(self.strict_zero_ios)
215
217
  return self.function_params.outputs
216
218
 
217
- @pydantic.validator("name", pre=True, always=True)
218
- def _create_name(cls, name: Optional[str], values: Dict[str, Any]) -> str:
219
+ @pydantic.field_validator("name", mode="before")
220
+ @classmethod
221
+ def _create_name(cls, name: Optional[str], info: ValidationInfo) -> str:
219
222
  """
220
223
  generates a name to a user defined-functions as follows:
221
224
  <function_name>_<SUFFIX_MARKER>_<random_suffix>
@@ -226,9 +229,9 @@ class SynthesisQuantumFunctionCall(BaseModel):
226
229
  raise ClassiqValueError(BAD_CALL_NAME_ERROR_MSG)
227
230
  return name
228
231
 
229
- function = values.get("function")
232
+ function = info.data.get("function")
230
233
 
231
- params = values.get("function_params")
234
+ params = info.data.get("function_params")
232
235
  if (
233
236
  isinstance(params, CustomFunction)
234
237
  and function == CustomFunction.discriminator()
@@ -241,25 +244,30 @@ class SynthesisQuantumFunctionCall(BaseModel):
241
244
  return name if name else suffix
242
245
  return f"{function.split(f'_{EXPANDED_KEYWORD}')[0]}_{suffix}"
243
246
 
244
- @pydantic.root_validator(pre=True)
245
- def validate_composite_name(cls, values: Dict[str, Any]) -> Dict[str, Any]:
246
- if isinstance(values.get("unitary_params"), CustomFunction) and not values.get(
247
- "unitary"
247
+ @pydantic.model_validator(mode="before")
248
+ @classmethod
249
+ def validate_composite_name(cls, values: Any) -> Dict[str, Any]:
250
+ if (
251
+ isinstance(values, dict)
252
+ and isinstance(values.get("unitary_params"), CustomFunction)
253
+ and not values.get("unitary")
248
254
  ):
249
255
  raise ClassiqValueError(
250
256
  "`PhaseEstimation` of a user define function (`CustomFunction`) must receive the function name from the `unitary` field"
251
257
  )
252
258
  return values
253
259
 
254
- @pydantic.root_validator(pre=True)
255
- def _parse_function_params(cls, values: Dict[str, Any]) -> Dict[str, Any]:
256
- f_params.parse_function_params_values(
257
- values=values,
258
- params_key="function_params",
259
- discriminator_key="function",
260
- param_classes=function_param_list.function_param_library.param_list,
261
- default_parser_class=CustomFunction,
262
- )
260
+ @pydantic.model_validator(mode="before")
261
+ @classmethod
262
+ def _parse_function_params(cls, values: Any) -> Dict[str, Any]:
263
+ if isinstance(values, dict):
264
+ f_params.parse_function_params_values(
265
+ values=values,
266
+ params_key="function_params",
267
+ discriminator_key="function",
268
+ param_classes=function_param_list.function_param_library.param_list,
269
+ default_parser_class=CustomFunction,
270
+ )
263
271
  return values
264
272
 
265
273
  # TODO: note that this checks QuantumFunctionCall input register names
@@ -295,22 +303,25 @@ class SynthesisQuantumFunctionCall(BaseModel):
295
303
  if error_msg:
296
304
  raise ClassiqValueError("\n".join(error_msg))
297
305
 
298
- @pydantic.validator("strict_zero_ios")
306
+ @pydantic.field_validator("strict_zero_ios")
307
+ @classmethod
299
308
  def _validate_arithmetic_cannot_strict_zero_ios(
300
- cls, strict_zero_ios: bool, values: Dict[str, Any]
309
+ cls, strict_zero_ios: bool, info: ValidationInfo
301
310
  ) -> bool:
302
311
  assert not (
303
- values.get("function") == Arithmetic.discriminator() and not strict_zero_ios
312
+ info.data.get("function") == Arithmetic.discriminator()
313
+ and not strict_zero_ios
304
314
  ), "when using the Arithmetic function, assign to the expression result register via the target parameter instead of the strict_zero_ios flag"
305
315
  return strict_zero_ios
306
316
 
307
- @pydantic.validator("control_states")
317
+ @pydantic.field_validator("control_states")
318
+ @classmethod
308
319
  def _validate_control_states(
309
- cls, control_states: List[ControlState], values: Dict[str, Any]
320
+ cls, control_states: List[ControlState], info: ValidationInfo
310
321
  ) -> List[ControlState]:
311
322
  control_names = [ctrl_state.name for ctrl_state in control_states]
312
- function_params = values.get("function_params")
313
- strict_zero_ios = values.get("strict_zero_ios")
323
+ function_params = info.data.get("function_params")
324
+ strict_zero_ios = info.data.get("strict_zero_ios")
314
325
  if not (
315
326
  isinstance(function_params, FunctionParams)
316
327
  and isinstance(strict_zero_ios, bool)
@@ -382,12 +393,13 @@ class SynthesisQuantumFunctionCall(BaseModel):
382
393
 
383
394
  return not any((empty_slices, out_of_range, overlapping_slices))
384
395
 
385
- @pydantic.validator("inputs")
386
- def _validate_inputs(cls, inputs: IOType, values: Dict[str, Any]) -> WireDict:
387
- params: Optional[FunctionParams] = values.get("function_params")
388
- is_inverse: bool = values.get("is_inverse", False)
389
- strict_zero_ios: bool = values.get("strict_zero_ios", True)
390
- control_states: List[ControlState] = values.get("control_states", list())
396
+ @pydantic.field_validator("inputs", mode="before")
397
+ @classmethod
398
+ def _validate_inputs(cls, inputs: IOType, info: ValidationInfo) -> WireDict:
399
+ params: Optional[FunctionParams] = info.data.get("function_params")
400
+ is_inverse: bool = info.data.get("is_inverse", False)
401
+ strict_zero_ios: bool = info.data.get("strict_zero_ios", True)
402
+ control_states: List[ControlState] = info.data.get("control_states", list())
391
403
  if params is None:
392
404
  return dict()
393
405
  if isinstance(params, CustomFunction):
@@ -452,12 +464,13 @@ class SynthesisQuantumFunctionCall(BaseModel):
452
464
  if error_msg:
453
465
  raise ClassiqValueError("\n".join(error_msg))
454
466
 
455
- @pydantic.validator("outputs")
456
- def _validate_outputs(cls, outputs: IOType, values: Dict[str, Any]) -> IOType:
457
- params = values.get("function_params")
458
- is_inverse: bool = values.get("is_inverse", False)
459
- strict_zero_ios: bool = values.get("strict_zero_ios", True)
460
- control_states = values.get("control_states", list())
467
+ @pydantic.field_validator("outputs", mode="before")
468
+ @classmethod
469
+ def _validate_outputs(cls, outputs: IOType, info: ValidationInfo) -> IOType:
470
+ params = info.data.get("function_params")
471
+ is_inverse: bool = info.data.get("is_inverse", False)
472
+ strict_zero_ios: bool = info.data.get("strict_zero_ios", True)
473
+ control_states = info.data.get("control_states", list())
461
474
  if params is None:
462
475
  return outputs
463
476
  if isinstance(params, CustomFunction):
@@ -492,15 +505,16 @@ class SynthesisQuantumFunctionCall(BaseModel):
492
505
 
493
506
  return outputs
494
507
 
495
- @pydantic.validator("power", always=True)
508
+ @pydantic.field_validator("power")
509
+ @classmethod
496
510
  def _validate_power(
497
- cls, power: pydantic.NonNegativeInt, values: Dict[str, Any]
511
+ cls, power: pydantic.NonNegativeInt, info: ValidationInfo
498
512
  ) -> pydantic.NonNegativeInt:
499
- function_params = values.get("function_params")
513
+ function_params = info.data.get("function_params")
500
514
  if function_params is None:
501
515
  return power
502
516
  if power != 1 and not function_params.is_powerable(
503
- values.get("strict_zero_ios")
517
+ info.data.get("strict_zero_ios")
504
518
  ):
505
519
  raise ClassiqValueError("Cannot power this operator")
506
520
  return power
@@ -633,8 +647,7 @@ class SynthesisQuantumFunctionCall(BaseModel):
633
647
  call_kwargs["control_states"] = self.control_states + [control_state]
634
648
  return SynthesisQuantumFunctionCall(**call_kwargs)
635
649
 
636
- class Config:
637
- extra = Extra.forbid
650
+ model_config = ConfigDict(extra="forbid")
638
651
 
639
652
 
640
653
  def _generate_single_io_err(