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,6 +1,7 @@
1
1
  from typing import Any, Dict, List, Optional, Tuple
2
2
 
3
3
  import pydantic
4
+ from pydantic import ConfigDict
4
5
 
5
6
  from classiq.interface.enum_utils import StrEnum
6
7
  from classiq.interface.generator.hardware.hardware_data import SynthesisHardwareData
@@ -23,7 +24,7 @@ class OperationType(StrEnum):
23
24
 
24
25
 
25
26
  class OperationData(pydantic.BaseModel):
26
- approximated_depth: Optional[int]
27
+ approximated_depth: Optional[int] = None
27
28
  width: int
28
29
  gate_count: Dict[str, int] = pydantic.Field(default_factory=dict)
29
30
 
@@ -34,7 +35,7 @@ class ProgramData(pydantic.BaseModel):
34
35
 
35
36
  class OperationParameter(pydantic.BaseModel):
36
37
  label: str
37
- value: Optional[str]
38
+ value: Optional[str] = None
38
39
 
39
40
 
40
41
  class OperationLink(pydantic.BaseModel):
@@ -43,8 +44,7 @@ class OperationLink(pydantic.BaseModel):
43
44
  qubits: Tuple[int, ...]
44
45
  type: str
45
46
 
46
- class Config:
47
- allow_mutation = False
47
+ model_config = ConfigDict(frozen=True)
48
48
 
49
49
  def __hash__(self) -> int:
50
50
  return hash((type(self), self.label, self.qubits, self.type))
@@ -59,6 +59,14 @@ class OperationLinks(pydantic.BaseModel):
59
59
  inputs: List[OperationLink]
60
60
  outputs: List[OperationLink]
61
61
 
62
+ @property
63
+ def input_width(self) -> int:
64
+ return sum(len(link.qubits) for link in self.inputs)
65
+
66
+ @property
67
+ def output_width(self) -> int:
68
+ return sum(len(link.qubits) for link in self.outputs)
69
+
62
70
 
63
71
  class AtomicGate(StrEnum):
64
72
  UNKNOWN = ""
@@ -89,12 +97,17 @@ class AtomicGate(StrEnum):
89
97
  CPHASE = "CPHASE"
90
98
  SWAP = "SWAP"
91
99
  IDENTITY = "IDENTITY"
100
+ U = "U"
101
+
102
+ @property
103
+ def is_control_gate(self) -> bool:
104
+ return self.startswith("C")
92
105
 
93
106
 
94
107
  class Operation(pydantic.BaseModel):
95
108
  name: str
96
109
  children: List["Operation"]
97
- operation_data: Optional[OperationData]
110
+ operation_data: Optional[OperationData] = None
98
111
  operation_links: OperationLinks
99
112
  control_qubits: Tuple[int, ...] = pydantic.Field(default_factory=tuple)
100
113
  auxiliary_qubits: Tuple[int, ...]
@@ -1 +1 @@
1
- INTERFACE_VERSION = "3"
1
+ INTERFACE_VERSION = "4"
classiq/interface/jobs.py CHANGED
@@ -2,7 +2,7 @@ from typing import Any, Dict, Generic, Optional, TypeVar, Union
2
2
 
3
3
  import pydantic
4
4
  from pydantic import BaseModel
5
- from pydantic.generics import GenericModel
5
+ from typing_extensions import Self
6
6
 
7
7
  from classiq.interface.enum_utils import StrEnum
8
8
  from classiq.interface.exceptions import ClassiqAPIError
@@ -41,33 +41,23 @@ For unsuccessful jobs, we expect failure_details to be a string and result to be
41
41
  """
42
42
 
43
43
 
44
- class JobDescription(GenericModel, Generic[T], json_encoders=CUSTOM_ENCODERS):
44
+ class JobDescription(BaseModel, Generic[T], json_encoders=CUSTOM_ENCODERS):
45
45
  status: JobStatus
46
- failure_details: Optional[str]
47
- result: Optional[T]
46
+ failure_details: Optional[str] = pydantic.Field(default=None)
47
+ result: Optional[T] = pydantic.Field(default=None)
48
48
 
49
- @pydantic.root_validator
50
- def validate_status_and_fields(cls, values: Dict[str, Any]) -> Dict[str, Any]:
51
- status: Optional[JobStatus] = values.get("status")
52
- if status is None or "result" not in values or "failure_details" not in values:
53
- # If any of the fields doesn't exist, then previous validations failed
54
- # result and failure_details are Optional, so we explicitly check if they
55
- # exist in the values dictionary
56
- return values
57
-
58
- result = values["result"]
59
- failure_details = values["failure_details"]
60
-
61
- if status is JobStatus.COMPLETED:
49
+ @pydantic.model_validator(mode="after")
50
+ def validate_status_and_fields(self) -> Self:
51
+ if self.status is JobStatus.COMPLETED:
62
52
  # Completed job must return result and not have an error
63
- if result is None or failure_details is not None:
53
+ if self.result is None or self.failure_details is not None:
64
54
  raise ClassiqAPIError(INVALID_RESPONSE_ERROR_MSG)
65
- elif status in (JobStatus.FAILED, JobStatus.CANCELLED):
55
+ elif self.status in (JobStatus.FAILED, JobStatus.CANCELLED):
66
56
  # Failed job must return error and not have result
67
- if result is not None or failure_details is None:
57
+ if self.result is not None or self.failure_details is None:
68
58
  raise ClassiqAPIError(INVALID_RESPONSE_ERROR_MSG)
69
- elif result is not None or failure_details is not None:
59
+ elif self.result is not None or self.failure_details is not None:
70
60
  # Pending job must have no result and no error
71
61
  raise ClassiqAPIError(INVALID_RESPONSE_ERROR_MSG)
72
62
 
73
- return values
63
+ return self
@@ -49,7 +49,8 @@ class BindOperation(QuantumOperation):
49
49
  for handle in self.out_handles
50
50
  ]
51
51
 
52
- @pydantic.validator("in_handles", "out_handles")
52
+ @pydantic.field_validator("in_handles", "out_handles")
53
+ @classmethod
53
54
  def validate_handle(cls, handles: List[HandleBinding]) -> List[HandleBinding]:
54
55
  for handle in handles:
55
56
  if not handle.is_bindable():
@@ -10,11 +10,11 @@ from classiq.interface.model.parameter import Parameter
10
10
 
11
11
  class AnonClassicalParameterDeclaration(Parameter):
12
12
  kind: Literal["ClassicalParameterDeclaration"]
13
-
14
13
  classical_type: ConcreteClassicalType
15
14
 
16
- @pydantic.root_validator(pre=True)
17
- def _set_kind(cls, values: Dict[str, Any]) -> Dict[str, Any]:
15
+ @pydantic.model_validator(mode="before")
16
+ @classmethod
17
+ def _set_kind(cls, values: Any) -> Dict[str, Any]:
18
18
  return values_with_discriminator(
19
19
  values, "kind", "ClassicalParameterDeclaration"
20
20
  )
@@ -25,7 +25,13 @@ class AnonClassicalParameterDeclaration(Parameter):
25
25
  ClassicalParameterDeclaration,
26
26
  ):
27
27
  raise ClassiqInternalError
28
- return ClassicalParameterDeclaration(**{**self.__dict__, "name": new_name})
28
+ return ClassicalParameterDeclaration(
29
+ **{
30
+ **self.__dict__,
31
+ "name": new_name,
32
+ "kind": "ClassicalParameterDeclaration",
33
+ }
34
+ )
29
35
 
30
36
 
31
37
  class ClassicalParameterDeclaration(AnonClassicalParameterDeclaration):
@@ -2,7 +2,7 @@ from itertools import chain
2
2
  from typing import TYPE_CHECKING, Any, Dict, Sequence, Union
3
3
 
4
4
  import pydantic
5
- from pydantic import Extra, Field
5
+ from pydantic import ConfigDict, Field
6
6
 
7
7
  from classiq.interface.ast_node import ASTNode
8
8
  from classiq.interface.generator.expressions.expression import Expression
@@ -12,10 +12,7 @@ HANDLE_ID_SEPARATOR = "___"
12
12
 
13
13
  class HandleBinding(ASTNode):
14
14
  name: str = Field(default=None)
15
-
16
- class Config:
17
- frozen = True
18
- extra = Extra.forbid
15
+ model_config = ConfigDict(frozen=True, extra="forbid")
19
16
 
20
17
  def __str__(self) -> str:
21
18
  return self.name
@@ -52,10 +49,18 @@ class HandleBinding(ASTNode):
52
49
  class NestedHandleBinding(HandleBinding):
53
50
  base_handle: "ConcreteHandleBinding"
54
51
 
55
- @pydantic.root_validator(pre=False)
56
- def _set_name(cls, values: Dict[str, Any]) -> Dict[str, Any]:
57
- if "base_handle" in values:
58
- values["name"] = values["base_handle"].name
52
+ @pydantic.model_validator(mode="before")
53
+ @classmethod
54
+ def _set_name(cls, values: Any) -> Dict[str, Any]:
55
+ if isinstance(values, dict):
56
+ orig = values
57
+ while "base_handle" in values:
58
+ values = values["base_handle"]
59
+ orig["name"] = dict(values).get("name")
60
+ return orig
61
+ if isinstance(values, NestedHandleBinding):
62
+ values.name = values.base_handle.name
63
+ return values.model_dump()
59
64
  return values
60
65
 
61
66
  def is_bindable(self) -> bool:
@@ -67,10 +72,7 @@ class NestedHandleBinding(HandleBinding):
67
72
 
68
73
  class SubscriptHandleBinding(NestedHandleBinding):
69
74
  index: Expression
70
-
71
- class Config:
72
- frozen = True
73
- extra = Extra.forbid
75
+ model_config = ConfigDict(frozen=True, extra="forbid")
74
76
 
75
77
  def __str__(self) -> str:
76
78
  return f"{self.base_handle}[{self.index}]"
@@ -121,10 +123,7 @@ class SubscriptHandleBinding(NestedHandleBinding):
121
123
  class SlicedHandleBinding(NestedHandleBinding):
122
124
  start: Expression
123
125
  end: Expression
124
-
125
- class Config:
126
- frozen = True
127
- extra = Extra.forbid
126
+ model_config = ConfigDict(frozen=True, extra="forbid")
128
127
 
129
128
  def __str__(self) -> str:
130
129
  return f"{self.base_handle}[{self.start}:{self.end}]"
@@ -191,10 +190,7 @@ class SlicedHandleBinding(NestedHandleBinding):
191
190
 
192
191
  class FieldHandleBinding(NestedHandleBinding):
193
192
  field: str
194
-
195
- class Config:
196
- frozen = True
197
- extra = Extra.forbid
193
+ model_config = ConfigDict(frozen=True, extra="forbid")
198
194
 
199
195
  def __str__(self) -> str:
200
196
  return f"{self.base_handle}.{self.field}"
@@ -222,6 +218,6 @@ ConcreteHandleBinding = Union[
222
218
  SlicedHandleBinding,
223
219
  FieldHandleBinding,
224
220
  ]
225
- SubscriptHandleBinding.update_forward_refs(ConcreteHandleBinding=ConcreteHandleBinding)
226
- SlicedHandleBinding.update_forward_refs(ConcreteHandleBinding=ConcreteHandleBinding)
227
- FieldHandleBinding.update_forward_refs(ConcreteHandleBinding=ConcreteHandleBinding)
221
+ SubscriptHandleBinding.model_rebuild()
222
+ SlicedHandleBinding.model_rebuild()
223
+ FieldHandleBinding.model_rebuild()
@@ -1,7 +1,7 @@
1
- from typing import Literal, Mapping, Sequence
1
+ from typing import Literal, Mapping, Sequence, Union
2
2
 
3
3
  from classiq.interface.enum_utils import StrEnum
4
- from classiq.interface.helpers.pydantic_model_helpers import nameables_to_dict
4
+ from classiq.interface.generator.expressions.expression import Expression
5
5
  from classiq.interface.model.handle_binding import ConcreteHandleBinding, HandleBinding
6
6
  from classiq.interface.model.quantum_statement import HandleMetadata, QuantumOperation
7
7
 
@@ -15,21 +15,28 @@ class InplaceBinaryOperation(QuantumOperation):
15
15
  kind: Literal["InplaceBinaryOperation"]
16
16
 
17
17
  target: ConcreteHandleBinding
18
- value: ConcreteHandleBinding
18
+ value: Union[ConcreteHandleBinding, Expression]
19
19
  operation: BinaryOperation
20
20
 
21
21
  @property
22
22
  def wiring_inouts(self) -> Mapping[str, HandleBinding]:
23
- return nameables_to_dict([self.target, self.value])
23
+ inouts = {self.target.name: self.target}
24
+ if isinstance(self.value, HandleBinding):
25
+ inouts[self.value.name] = self.value
26
+ return inouts
24
27
 
25
28
  @property
26
29
  def readable_inouts(self) -> Sequence[HandleMetadata]:
27
30
  suffix = f" of an in-place {self.operation.name.lower()} statement"
28
- return [
31
+ readable_inouts = [
29
32
  HandleMetadata(
30
33
  handle=self.target, readable_location=f"as the target{suffix}"
31
- ),
32
- HandleMetadata(
33
- handle=self.value, readable_location=f"as the value{suffix}"
34
- ),
34
+ )
35
35
  ]
36
+ if isinstance(self.value, HandleBinding):
37
+ readable_inouts.append(
38
+ HandleMetadata(
39
+ handle=self.value, readable_location=f"as the value{suffix}"
40
+ )
41
+ )
42
+ return readable_inouts
@@ -1,5 +1,5 @@
1
1
  from collections import Counter
2
- from typing import List, Literal, Mapping, NewType
2
+ from typing import Any, List, Literal, Mapping, NewType
3
3
 
4
4
  import pydantic
5
5
 
@@ -61,6 +61,7 @@ class Model(VersionedModel, ASTNode):
61
61
  functions: List[NativeFunctionDefinition] = pydantic.Field(
62
62
  default_factory=list,
63
63
  description="The user-defined custom type library.",
64
+ validate_default=True,
64
65
  )
65
66
 
66
67
  enums: List[EnumDeclaration] = pydantic.Field(
@@ -105,9 +106,17 @@ class Model(VersionedModel, ASTNode):
105
106
  def body(self) -> StatementBlock:
106
107
  return self.main_func.body
107
108
 
108
- @pydantic.validator("preferences", always=True)
109
- def _seed_suffix_randomizer(cls, preferences: Preferences) -> Preferences:
110
- SUFFIX_RANDOMIZER.seed(preferences.random_seed)
109
+ @pydantic.field_validator("preferences", mode="before")
110
+ @classmethod
111
+ def _seed_suffix_randomizer(cls, preferences: Any) -> Any:
112
+ if isinstance(preferences, dict):
113
+ SUFFIX_RANDOMIZER.seed(preferences.get("random_seed"))
114
+ elif isinstance(preferences, Preferences):
115
+ SUFFIX_RANDOMIZER.seed(preferences.random_seed)
116
+ else:
117
+ raise ClassiqValueError(
118
+ f"preferences must be either a dict or a Preferences object, not {type(preferences)}"
119
+ )
111
120
  return preferences
112
121
 
113
122
  def _get_qualified_direction(
@@ -121,7 +130,8 @@ class Model(VersionedModel, ASTNode):
121
130
  def function_dict(self) -> Mapping[str, NamedParamsQuantumFunctionDeclaration]:
122
131
  return nameables_to_dict(self.functions)
123
132
 
124
- @pydantic.validator("functions", always=True)
133
+ @pydantic.field_validator("functions")
134
+ @classmethod
125
135
  def _add_empty_main(
126
136
  cls, functions: List[NativeFunctionDefinition]
127
137
  ) -> List[NativeFunctionDefinition]:
@@ -131,11 +141,10 @@ class Model(VersionedModel, ASTNode):
131
141
  return functions
132
142
 
133
143
  def get_model(self) -> SerializedModel:
134
- return SerializedModel(
135
- self.json(exclude_defaults=True, exclude_unset=True, indent=2)
136
- )
144
+ return SerializedModel(self.model_dump_json(indent=2))
137
145
 
138
- @pydantic.validator("functions")
146
+ @pydantic.field_validator("functions")
147
+ @classmethod
139
148
  def _validate_entry_point(
140
149
  cls, functions: List[NativeFunctionDefinition]
141
150
  ) -> List[NativeFunctionDefinition]:
@@ -150,7 +159,8 @@ class Model(VersionedModel, ASTNode):
150
159
 
151
160
  return functions
152
161
 
153
- @pydantic.validator("constants")
162
+ @pydantic.field_validator("constants")
163
+ @classmethod
154
164
  def _validate_constants(cls, constants: List[Constant]) -> List[Constant]:
155
165
  constant_definition_counts = Counter(
156
166
  [constant.name for constant in constants]
@@ -166,7 +176,7 @@ class Model(VersionedModel, ASTNode):
166
176
  return constants
167
177
 
168
178
  def json_no_preferences_and_constraints(self) -> str:
169
- return self.json(
179
+ return self.model_dump_json(
170
180
  indent=2,
171
181
  exclude={
172
182
  "constraints",
@@ -10,6 +10,13 @@ if TYPE_CHECKING:
10
10
  from classiq.interface.model.statement_block import StatementBlock
11
11
 
12
12
 
13
+ class FunctionSynthesisData(pydantic.BaseModel):
14
+ should_synthesize_separately: bool = pydantic.Field(
15
+ default=False,
16
+ description="Whether the function should be synthesized separately.",
17
+ )
18
+
19
+
13
20
  class NativeFunctionDefinition(NamedParamsQuantumFunctionDeclaration):
14
21
  """
15
22
  Facilitates the creation of a user-defined composite function
@@ -21,3 +28,6 @@ class NativeFunctionDefinition(NamedParamsQuantumFunctionDeclaration):
21
28
  body: "StatementBlock" = pydantic.Field(
22
29
  default_factory=list, description="List of function calls to perform."
23
30
  )
31
+ synthesis_data: FunctionSynthesisData = pydantic.Field(
32
+ default_factory=FunctionSynthesisData,
33
+ )
@@ -1,6 +1,7 @@
1
- from typing import Any, Dict, Literal, Mapping
1
+ from typing import Any, Dict, Literal
2
2
 
3
3
  import pydantic
4
+ from pydantic_core.core_schema import ValidationInfo
4
5
 
5
6
  from classiq.interface.exceptions import ClassiqInternalError, ClassiqValueError
6
7
  from classiq.interface.generator.functions.concrete_types import ConcreteQuantumType
@@ -12,19 +13,21 @@ from classiq.interface.model.parameter import Parameter
12
13
 
13
14
 
14
15
  class AnonPortDeclaration(Parameter):
15
- kind: Literal["PortDeclaration"]
16
-
17
16
  quantum_type: ConcreteQuantumType
18
17
  direction: PortDeclarationDirection
18
+ kind: Literal["PortDeclaration"]
19
19
 
20
- @pydantic.root_validator(pre=True)
21
- def _set_kind(cls, values: Dict[str, Any]) -> Dict[str, Any]:
20
+ @pydantic.model_validator(mode="before")
21
+ @classmethod
22
+ def _set_kind(cls, values: Any) -> Dict[str, Any]:
22
23
  return values_with_discriminator(values, "kind", "PortDeclaration")
23
24
 
24
- @pydantic.validator("direction")
25
+ @pydantic.field_validator("direction", mode="before")
26
+ @classmethod
25
27
  def _direction_validator(
26
- cls, direction: PortDeclarationDirection, values: Mapping[str, Any]
28
+ cls, direction: PortDeclarationDirection, info: ValidationInfo
27
29
  ) -> PortDeclarationDirection:
30
+ values = info.data
28
31
  if direction is PortDeclarationDirection.Output:
29
32
  quantum_type = values.get("quantum_type")
30
33
  if quantum_type is None:
@@ -1,6 +1,7 @@
1
1
  from typing import Dict, Literal, Mapping, Optional, Sequence
2
2
 
3
3
  import pydantic
4
+ from pydantic_core.core_schema import ValidationInfo
4
5
 
5
6
  from classiq.interface.enum_utils import StrEnum
6
7
  from classiq.interface.generator.arith.arithmetic import (
@@ -34,17 +35,18 @@ class ArithmeticOperation(QuantumAssignmentOperation):
34
35
  )
35
36
 
36
37
  operation_kind: ArithmeticOperationKind = pydantic.Field(
37
- default=None,
38
+ default=None, validate_default=True
38
39
  )
39
40
 
40
- @pydantic.validator("operation_kind", always=True)
41
+ @pydantic.field_validator("operation_kind", mode="before")
42
+ @classmethod
41
43
  def _propagate_inplace_result(
42
- cls, operation_kind: Optional[ArithmeticOperationKind], values: dict
44
+ cls, operation_kind: Optional[ArithmeticOperationKind], info: ValidationInfo
43
45
  ) -> ArithmeticOperationKind:
44
46
  if operation_kind is None:
45
47
  operation_kind = (
46
48
  ArithmeticOperationKind.InplaceXor
47
- if values["inplace_result"]
49
+ if info.data["inplace_result"]
48
50
  else ArithmeticOperationKind.Assignment
49
51
  )
50
52
  return operation_kind
@@ -8,6 +8,8 @@ from typing import (
8
8
  )
9
9
 
10
10
  import pydantic
11
+ from pydantic import SerializeAsAny
12
+ from pydantic_core.core_schema import ValidationInfo
11
13
  from typing_extensions import Annotated
12
14
 
13
15
  from classiq.interface.exceptions import ClassiqInternalError
@@ -143,7 +145,7 @@ class AnonQuantumFunctionDeclaration(FunctionDeclaration):
143
145
  **{
144
146
  field_name: field_value
145
147
  for field_name, field_value in self.__dict__.items()
146
- if field_name in AnonQuantumFunctionDeclaration.__fields__
148
+ if field_name in AnonQuantumFunctionDeclaration.model_fields
147
149
  },
148
150
  "name": new_name,
149
151
  }
@@ -158,17 +160,21 @@ class AnonQuantumOperandDeclaration(AnonQuantumFunctionDeclaration):
158
160
  default=False,
159
161
  )
160
162
 
161
- @pydantic.root_validator(pre=True)
162
- def _set_kind(cls, values: Dict[str, Any]) -> Dict[str, Any]:
163
+ @pydantic.model_validator(mode="before")
164
+ @classmethod
165
+ def _set_kind(cls, values: Any) -> Dict[str, Any]:
163
166
  return values_with_discriminator(values, "kind", "QuantumOperandDeclaration")
164
167
 
165
168
  def rename(self, new_name: str) -> "QuantumOperandDeclaration":
166
169
  if type(self) not in (AnonQuantumOperandDeclaration, QuantumOperandDeclaration):
167
170
  raise ClassiqInternalError
168
- return QuantumOperandDeclaration(**{**self.__dict__, "name": new_name})
171
+ new_instance_data = self.__dict__.copy()
172
+ new_instance_data["name"] = new_name
173
+ new_instance_data["kind"] = "QuantumOperandDeclaration"
174
+ return QuantumOperandDeclaration(**new_instance_data)
169
175
 
170
176
 
171
- AnonQuantumFunctionDeclaration.update_forward_refs()
177
+ AnonQuantumFunctionDeclaration.model_rebuild()
172
178
 
173
179
 
174
180
  class QuantumFunctionDeclaration(AnonQuantumFunctionDeclaration):
@@ -176,16 +182,21 @@ class QuantumFunctionDeclaration(AnonQuantumFunctionDeclaration):
176
182
 
177
183
 
178
184
  class QuantumOperandDeclaration(
179
- QuantumFunctionDeclaration, AnonQuantumOperandDeclaration
185
+ AnonQuantumOperandDeclaration, QuantumFunctionDeclaration
180
186
  ):
181
- pass
187
+ @pydantic.model_validator(mode="before")
188
+ @classmethod
189
+ def _set_none(cls, values: Any, info: ValidationInfo) -> Dict[str, Any]:
190
+ return values
182
191
 
183
192
 
184
193
  PositionalArg = Annotated[
185
- Union[
186
- ClassicalParameterDeclaration,
187
- QuantumOperandDeclaration,
188
- PortDeclaration,
194
+ SerializeAsAny[
195
+ Union[
196
+ ClassicalParameterDeclaration,
197
+ QuantumOperandDeclaration,
198
+ PortDeclaration,
199
+ ]
189
200
  ],
190
201
  pydantic.Field(..., discriminator="kind"),
191
202
  ]
@@ -3,7 +3,7 @@ from typing import Any, Callable, Dict, Mapping, Optional, Sequence
3
3
  from uuid import UUID, uuid4
4
4
 
5
5
  import pydantic
6
- from pydantic import Extra, root_validator
6
+ from pydantic import ConfigDict
7
7
 
8
8
  from classiq.interface.ast_node import ASTNode
9
9
  from classiq.interface.helpers.pydantic_model_helpers import values_with_discriminator
@@ -15,13 +15,12 @@ from classiq.interface.model.handle_binding import (
15
15
 
16
16
  class QuantumStatement(ASTNode):
17
17
  kind: str
18
+ model_config = ConfigDict(extra="forbid")
18
19
 
19
- class Config:
20
- extra = Extra.forbid
21
-
22
- @root_validator(pre=True)
23
- def _set_kind(cls, values: Dict[str, Any]) -> Dict[str, Any]:
24
- return values_with_discriminator(values, "kind", cls.__name__) # type: ignore[attr-defined]
20
+ @pydantic.model_validator(mode="before")
21
+ @classmethod
22
+ def _set_kind(cls, values: Any) -> Dict[str, Any]:
23
+ return values_with_discriminator(values, "kind", cls.__name__)
25
24
 
26
25
 
27
26
  @dataclass
@@ -1,7 +1,8 @@
1
1
  from typing import TYPE_CHECKING, Any, Dict, Literal, Optional
2
2
 
3
3
  import pydantic
4
- from pydantic import BaseModel, Extra, Field
4
+ from pydantic import BaseModel, ConfigDict, Field
5
+ from typing_extensions import Self
5
6
 
6
7
  from classiq.interface.ast_node import HashableASTNode
7
8
  from classiq.interface.exceptions import ClassiqValueError
@@ -25,8 +26,7 @@ if TYPE_CHECKING:
25
26
 
26
27
 
27
28
  class QuantumType(HashableASTNode):
28
- class Config:
29
- extra = Extra.forbid
29
+ model_config = ConfigDict(extra="forbid")
30
30
 
31
31
  _size_in_bits: Optional[int] = pydantic.PrivateAttr(default=None)
32
32
 
@@ -72,8 +72,9 @@ class QuantumBit(QuantumScalar):
72
72
  super().__init__(**kwargs)
73
73
  self._size_in_bits = 1
74
74
 
75
- @pydantic.root_validator(pre=True)
76
- def _set_kind(cls, values: Dict[str, Any]) -> Dict[str, Any]:
75
+ @pydantic.model_validator(mode="before")
76
+ @classmethod
77
+ def _set_kind(cls, values: Any) -> Dict[str, Any]:
77
78
  return values_with_discriminator(values, "kind", "qbit")
78
79
 
79
80
  @property
@@ -89,14 +90,15 @@ class QuantumBit(QuantumScalar):
89
90
 
90
91
 
91
92
  class QuantumBitvector(QuantumType):
92
- kind: Literal["qvec"]
93
93
  element_type: "ConcreteQuantumType" = Field(
94
94
  discriminator="kind", default_factory=QuantumBit
95
95
  )
96
- length: Optional[Expression]
96
+ kind: Literal["qvec"]
97
+ length: Optional[Expression] = Field(default=None)
97
98
 
98
- @pydantic.root_validator(pre=True)
99
- def _set_kind(cls, values: Dict[str, Any]) -> Dict[str, Any]:
99
+ @pydantic.model_validator(mode="before")
100
+ @classmethod
101
+ def _set_kind(cls, values: Any) -> Dict[str, Any]:
100
102
  return values_with_discriminator(values, "kind", "qvec")
101
103
 
102
104
  def _update_size_in_bits_from_declaration(self) -> None:
@@ -144,23 +146,24 @@ class QuantumBitvector(QuantumType):
144
146
  class QuantumNumeric(QuantumScalar):
145
147
  kind: Literal["qnum"]
146
148
 
147
- size: Optional[Expression] = pydantic.Field()
148
- is_signed: Optional[Expression] = pydantic.Field()
149
- fraction_digits: Optional[Expression] = pydantic.Field()
149
+ size: Optional[Expression] = pydantic.Field(default=None)
150
+ is_signed: Optional[Expression] = pydantic.Field(default=None)
151
+ fraction_digits: Optional[Expression] = pydantic.Field(default=None)
150
152
 
151
- @pydantic.root_validator(pre=True)
152
- def _set_kind(cls, values: Dict[str, Any]) -> Dict[str, Any]:
153
+ @pydantic.model_validator(mode="before")
154
+ @classmethod
155
+ def _set_kind(cls, values: Any) -> Dict[str, Any]:
153
156
  return values_with_discriminator(values, "kind", "qnum")
154
157
 
155
- @pydantic.root_validator
156
- def _validate_fields(cls, values: Dict[str, Any]) -> Dict[str, Any]:
157
- has_sign = values["is_signed"] is not None
158
- has_fraction_digits = values["fraction_digits"] is not None
158
+ @pydantic.model_validator(mode="after")
159
+ def _validate_fields(self) -> Self:
160
+ has_sign = self.is_signed is not None
161
+ has_fraction_digits = self.fraction_digits is not None
159
162
  if has_sign and not has_fraction_digits or not has_sign and has_fraction_digits:
160
163
  raise ClassiqValueError(
161
164
  "Assign neither or both of is_signed and fraction_digits"
162
165
  )
163
- return values
166
+ return self
164
167
 
165
168
  @property
166
169
  def has_sign(self) -> bool: