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, Optional
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.function_params import (
@@ -26,44 +27,53 @@ _DEFAULT_ORACLE_DISCRIMINATOR: FunctionParamsDiscriminator = (
26
27
 
27
28
  class GroverOperator(FunctionParams):
28
29
  oracle: str = pydantic.Field(
29
- default=_DEFAULT_ORACLE_DISCRIMINATOR, description="Oracle function"
30
+ default=_DEFAULT_ORACLE_DISCRIMINATOR,
31
+ description="Oracle function",
32
+ validate_default=True,
30
33
  )
31
34
  oracle_params: OracleABC = pydantic.Field(description="Oracle function parameters")
32
35
  state_preparation: str = pydantic.Field(
33
- default="", description="State preparation function"
36
+ default="",
37
+ description="State preparation function",
38
+ validate_default=True,
34
39
  )
35
40
  state_preparation_params: GroverStatePreparation = pydantic.Field(
36
- default=None, description="State preparation function parameters"
41
+ default=None,
42
+ description="State preparation function parameters",
43
+ validate_default=True,
37
44
  )
38
45
 
39
46
  def _create_ios(self) -> None:
40
47
  self._inputs = {**self.oracle_params.inputs}
41
48
  self._outputs = {**self.oracle_params.outputs}
42
49
 
43
- @pydantic.root_validator(pre=True)
44
- def _parse_oracle(cls, values: Dict[str, Any]) -> Dict[str, Any]:
45
- oracle_params = values.get("oracle_params")
46
- if isinstance(oracle_params, dict):
47
- values["oracle_params"] = parse_function_params(
48
- params=oracle_params,
49
- discriminator=values.get("oracle", _DEFAULT_ORACLE_DISCRIMINATOR),
50
- param_classes=oracle_function_param_library.param_list,
51
- no_discriminator_error=ClassiqValueError("Invalid oracle name"),
52
- bad_function_error=ClassiqValueError("Invalid oracle params"),
53
- )
54
- elif isinstance(oracle_params, FunctionParams):
55
- values["oracle"] = oracle_params.discriminator()
56
- else:
57
- raise ClassiqValueError("Invalid oracle params")
50
+ @pydantic.model_validator(mode="before")
51
+ @classmethod
52
+ def _parse_oracle(cls, values: Any) -> Dict[str, Any]:
53
+ if isinstance(values, dict):
54
+ oracle_params = values.get("oracle_params")
55
+ if isinstance(oracle_params, dict):
56
+ values["oracle_params"] = parse_function_params(
57
+ params=oracle_params,
58
+ discriminator=values.get("oracle", _DEFAULT_ORACLE_DISCRIMINATOR),
59
+ param_classes=oracle_function_param_library.param_list,
60
+ no_discriminator_error=ClassiqValueError("Invalid oracle name"),
61
+ bad_function_error=ClassiqValueError("Invalid oracle params"),
62
+ )
63
+ elif isinstance(oracle_params, FunctionParams):
64
+ values["oracle"] = oracle_params.discriminator()
65
+ else:
66
+ raise ClassiqValueError("Invalid oracle params")
58
67
  return values
59
68
 
60
- @pydantic.validator("state_preparation_params", always=True)
69
+ @pydantic.field_validator("state_preparation_params", mode="before")
70
+ @classmethod
61
71
  def _validate_state_preparation(
62
72
  cls,
63
73
  state_preparation_params: Optional[GroverStatePreparation],
64
- values: Dict[str, Any],
74
+ info: ValidationInfo,
65
75
  ) -> GroverStatePreparation:
66
- oracle = values.get("oracle_params")
76
+ oracle = info.data.get("oracle_params")
67
77
  assert oracle is not None, "Must receive an oracle"
68
78
  state_preparation_params = (
69
79
  state_preparation_params
@@ -73,7 +83,7 @@ class GroverOperator(FunctionParams):
73
83
  )
74
84
  assert GroverDiffuser(
75
85
  state_preparation_params=state_preparation_params,
76
- state_preparation=values.get("state_preparation", ""),
86
+ state_preparation=info.data.get("state_preparation", ""),
77
87
  variables=oracle.variables(),
78
88
  ), "Cannot construct a GroverDiffuser"
79
89
  return state_preparation_params
@@ -23,9 +23,7 @@ class ExponentiationConstraints(pydantic.BaseModel):
23
23
  default=None,
24
24
  description="Maximum approximation error of the exponentiation circuit.",
25
25
  )
26
-
27
- class Config:
28
- frozen = True
26
+ model_config = pydantic.ConfigDict(frozen=True)
29
27
 
30
28
 
31
29
  class Exponentiation(HamiltonianEvolution):
@@ -45,6 +43,7 @@ class Exponentiation(HamiltonianEvolution):
45
43
  description="What attribute to optimize.",
46
44
  )
47
45
 
48
- @pydantic.validator("pauli_operator")
46
+ @pydantic.field_validator("pauli_operator")
47
+ @classmethod
49
48
  def _validate_is_hermitian(cls, pauli_operator: PauliOperator) -> PauliOperator:
50
49
  return operator.validate_operator_is_hermitian(pauli_operator)
@@ -2,10 +2,10 @@ import pydantic
2
2
 
3
3
  from classiq.interface.chemistry import operator
4
4
  from classiq.interface.chemistry.operator import PauliOperator
5
+ from classiq.interface.generator.function_params import FunctionParamsNumericParameter
5
6
  from classiq.interface.generator.hamiltonian_evolution.hamiltonian_evolution import (
6
7
  HamiltonianEvolution,
7
8
  )
8
- from classiq.interface.generator.parameters import ParameterFloatType
9
9
 
10
10
 
11
11
  class QDrift(HamiltonianEvolution):
@@ -13,15 +13,15 @@ class QDrift(HamiltonianEvolution):
13
13
  qDrift trotterization of a Hermitian operator; see https://arxiv.org/abs/1811.08017
14
14
  """
15
15
 
16
- evolution_coefficient: ParameterFloatType = pydantic.Field(
16
+ evolution_coefficient: FunctionParamsNumericParameter = pydantic.Field(
17
17
  default=1.0,
18
18
  description="A global coefficient multiplying the operator.",
19
- is_exec_param=True,
20
19
  )
21
20
  num_qdrift: pydantic.PositiveInt = pydantic.Field(
22
21
  description="The number of elements in the qDrift product.",
23
22
  )
24
23
 
25
- @pydantic.validator("pauli_operator")
24
+ @pydantic.field_validator("pauli_operator")
25
+ @classmethod
26
26
  def _validate_is_hermitian(cls, pauli_operator: PauliOperator) -> PauliOperator:
27
27
  return operator.validate_operator_is_hermitian(pauli_operator)
@@ -1,12 +1,13 @@
1
1
  import pydantic
2
+ from pydantic import ConfigDict
2
3
 
3
4
  from classiq.interface.chemistry import operator
4
5
  from classiq.interface.chemistry.operator import PauliOperator
5
6
  from classiq.interface.exceptions import ClassiqValueError
7
+ from classiq.interface.generator.function_params import FunctionParamsNumericParameter
6
8
  from classiq.interface.generator.hamiltonian_evolution.hamiltonian_evolution import (
7
9
  HamiltonianEvolution,
8
10
  )
9
- from classiq.interface.generator.parameters import ParameterFloatType
10
11
 
11
12
 
12
13
  class SuzukiParameters(pydantic.BaseModel):
@@ -18,7 +19,8 @@ class SuzukiParameters(pydantic.BaseModel):
18
19
  default=1, description="The number of repetitions in the Suzuki-Trotter"
19
20
  )
20
21
 
21
- @pydantic.validator("order")
22
+ @pydantic.field_validator("order")
23
+ @classmethod
22
24
  def _validate_order(cls, order: int) -> int:
23
25
  if order != 1 and order % 2:
24
26
  raise ClassiqValueError(
@@ -26,8 +28,7 @@ class SuzukiParameters(pydantic.BaseModel):
26
28
  )
27
29
  return order
28
30
 
29
- class Config:
30
- frozen = True
31
+ model_config = ConfigDict(frozen=True)
31
32
 
32
33
 
33
34
  class SuzukiTrotter(HamiltonianEvolution):
@@ -35,10 +36,9 @@ class SuzukiTrotter(HamiltonianEvolution):
35
36
  Suzuki trotterization of a Hermitian operator
36
37
  """
37
38
 
38
- evolution_coefficient: ParameterFloatType = pydantic.Field(
39
+ evolution_coefficient: FunctionParamsNumericParameter = pydantic.Field(
39
40
  default=1.0,
40
41
  description="A global coefficient multiplying the operator.",
41
- is_exec_param=True,
42
42
  )
43
43
  suzuki_parameters: SuzukiParameters = pydantic.Field(
44
44
  default_factory=SuzukiParameters, description="The Suziki parameters."
@@ -47,7 +47,8 @@ class SuzukiTrotter(HamiltonianEvolution):
47
47
  default=False, description="Whether to disable the reordering of Pauli terms."
48
48
  )
49
49
 
50
- @pydantic.validator("pauli_operator")
50
+ @pydantic.field_validator("pauli_operator")
51
+ @classmethod
51
52
  def _validate_no_complex_coefficients(
52
53
  cls, pauli_operator: PauliOperator
53
54
  ) -> PauliOperator:
@@ -3,6 +3,7 @@ from collections import defaultdict
3
3
  from typing import Any, Dict, List, MutableSet, Optional
4
4
 
5
5
  import pydantic
6
+ from typing_extensions import Self
6
7
 
7
8
  from classiq.interface.backend.backend_preferences import BackendPreferences
8
9
  from classiq.interface.exceptions import ClassiqValueError
@@ -60,7 +61,8 @@ class HardwareData(pydantic.BaseModel):
60
61
  "If false, the first / second qubit denotes the control / target, respectively",
61
62
  )
62
63
 
63
- @pydantic.validator("connectivity_map")
64
+ @pydantic.field_validator("connectivity_map")
65
+ @classmethod
64
66
  def _validate_connectivity_map(
65
67
  cls, connectivity_map: Optional[ConnectivityMap]
66
68
  ) -> Optional[ConnectivityMap]:
@@ -71,39 +73,37 @@ class HardwareData(pydantic.BaseModel):
71
73
  connectivity_map = _reindex_qubits(connectivity_map)
72
74
  return connectivity_map
73
75
 
74
- @pydantic.root_validator()
75
- def _symmetrize_connectivity_map(cls, values: Dict[str, Any]) -> Dict[str, Any]:
76
- connectivity_map = values.get("connectivity_map")
76
+ @pydantic.model_validator(mode="after")
77
+ def _symmetrize_connectivity_map(self) -> Self:
78
+ connectivity_map = self.connectivity_map
77
79
  if connectivity_map is None:
78
- return values
80
+ return self
79
81
 
80
- is_symmetric = values.get("is_symmetric_connectivity")
82
+ is_symmetric = self.is_symmetric_connectivity
81
83
  if is_symmetric:
82
84
  connectivity_map = _symmetrize_connectivity_map(connectivity_map)
83
- values["connectivity_map"] = connectivity_map
85
+ self.connectivity_map = connectivity_map
84
86
 
85
87
  if not _is_connected_map(connectivity_map):
86
88
  raise ClassiqValueError(
87
89
  f"Connectivity map must be connected: {connectivity_map} is not connected."
88
90
  )
89
- return values
91
+ return self
90
92
 
91
- @pydantic.root_validator()
92
- def _validate_basis_gates(cls, values: Dict[str, Any]) -> Dict[str, Any]:
93
- connectivity_map = values.get("connectivity_map")
94
- specified_basis_gates = values.get("basis_gates", [])
93
+ @pydantic.model_validator(mode="after")
94
+ def _validate_basis_gates(self) -> Self:
95
+ connectivity_map = self.connectivity_map
96
+ specified_basis_gates = self.basis_gates
95
97
  if connectivity_map is None:
96
- values["basis_gates"] = specified_basis_gates or list(DEFAULT_BASIS_GATES)
97
- return values
98
+ self.basis_gates = specified_basis_gates or list(DEFAULT_BASIS_GATES)
99
+ return self
98
100
 
99
- is_symmetric_connectivity = values.get("is_symmetric")
101
+ is_symmetric_connectivity = self.is_symmetric_connectivity
100
102
  if is_symmetric_connectivity or _check_symmetry(connectivity_map):
101
- values["basis_gates"] = specified_basis_gates or list(DEFAULT_BASIS_GATES)
102
- return values
103
+ self.basis_gates = specified_basis_gates or list(DEFAULT_BASIS_GATES)
104
+ return self
103
105
 
104
- values["basis_gates"] = specified_basis_gates or list(
105
- DEFAULT_ROUTING_BASIS_GATES
106
- )
106
+ self.basis_gates = specified_basis_gates or list(DEFAULT_ROUTING_BASIS_GATES)
107
107
  invalid_gates = [
108
108
  gate
109
109
  for gate in specified_basis_gates
@@ -115,7 +115,7 @@ class HardwareData(pydantic.BaseModel):
115
115
  "is currently supported for the following two-qubit gates only: cx, ecr, rzx."
116
116
  )
117
117
 
118
- return values
118
+ return self
119
119
 
120
120
 
121
121
  class CustomHardwareSettings(HardwareData):
@@ -127,7 +127,8 @@ class CustomHardwareSettings(HardwareData):
127
127
 
128
128
  _width: Optional[int] = pydantic.PrivateAttr(default=None)
129
129
 
130
- @pydantic.validator("basis_gates")
130
+ @pydantic.field_validator("basis_gates", mode="after")
131
+ @classmethod
131
132
  def validate_basis_gates(cls, basis_gates: List[str]) -> List[TranspilerBasisGates]:
132
133
  valid_gates = list(TranspilerBasisGates)
133
134
  invalid_gates = [gate for gate in basis_gates if gate not in valid_gates]
@@ -179,7 +180,7 @@ def _node_dfs(
179
180
 
180
181
  def _reindex_qubits(connectivity_map: ConnectivityMap) -> ConnectivityMap:
181
182
  qubits = sorted({q for pair in connectivity_map for q in pair})
182
- return [(qubits.index(pair[0]), qubits.index(pair[1])) for pair in connectivity_map]
183
+ return [[qubits.index(pair[0]), qubits.index(pair[1])] for pair in connectivity_map]
183
184
 
184
185
 
185
186
  def _check_symmetry(connectivity_map: ConnectivityMap) -> bool:
@@ -191,14 +192,14 @@ def _symmetrize_connectivity_map(connectivity_map: ConnectivityMap) -> Connectiv
191
192
  # A more complicated implementation than using set to maintain the order
192
193
  connectivity_map_no_duplicates = []
193
194
  for edge in connectivity_map:
194
- reversed_edge = (edge[1], edge[0])
195
+ reversed_edge = [edge[1], edge[0]]
195
196
  if (
196
197
  edge not in connectivity_map_no_duplicates
197
198
  and reversed_edge not in connectivity_map_no_duplicates
198
199
  ):
199
200
  connectivity_map_no_duplicates.append(edge)
200
201
  reversed_connectivity_map = [
201
- (edge[1], edge[0]) for edge in connectivity_map_no_duplicates
202
+ [edge[1], edge[0]] for edge in connectivity_map_no_duplicates
202
203
  ]
203
204
  return connectivity_map_no_duplicates + reversed_connectivity_map
204
205
 
@@ -217,4 +218,4 @@ class SynthesisHardwareData(HardwareData):
217
218
  Defaults to `None`.
218
219
  """
219
220
 
220
- backend_data: Optional[BackendPreferences]
221
+ backend_data: Optional[BackendPreferences] = pydantic.Field(default=None)
@@ -1,7 +1,8 @@
1
1
  import itertools
2
- from typing import TYPE_CHECKING, Any, Dict, List, Optional, Union
2
+ from typing import TYPE_CHECKING, List, Optional, Union
3
3
 
4
4
  import pydantic
5
+ from pydantic_core.core_schema import ValidationInfo
5
6
 
6
7
  from classiq.interface.enum_utils import StrEnum
7
8
  from classiq.interface.exceptions import ClassiqValueError
@@ -44,6 +45,7 @@ class HardwareEfficientAnsatz(function_params.FunctionParams):
44
45
  num_qubits: pydantic.PositiveInt = pydantic.Field(
45
46
  default=None,
46
47
  description="Number of qubits in the ansatz.",
48
+ validate_default=True,
47
49
  )
48
50
  reps: pydantic.PositiveInt = pydantic.Field(
49
51
  default=1, description="Number of layers in the Ansatz"
@@ -62,11 +64,12 @@ class HardwareEfficientAnsatz(function_params.FunctionParams):
62
64
  description="Prefix for the generated parameters",
63
65
  )
64
66
 
65
- @pydantic.validator("num_qubits", pre=True, always=True)
67
+ @pydantic.field_validator("num_qubits", mode="before")
68
+ @classmethod
66
69
  def validate_num_qubits(
67
- cls, num_qubits: Optional[pydantic.PositiveInt], values: Dict[str, Any]
70
+ cls, num_qubits: Optional[pydantic.PositiveInt], info: ValidationInfo
68
71
  ) -> pydantic.PositiveInt:
69
- connectivity_map = values.get("connectivity_map")
72
+ connectivity_map = info.data.get("connectivity_map")
70
73
  conn_map_is_not_list = (
71
74
  isinstance(connectivity_map, SupportedConnectivityMaps)
72
75
  or connectivity_map is None
@@ -101,7 +104,8 @@ class HardwareEfficientAnsatz(function_params.FunctionParams):
101
104
  )
102
105
  return num_qubits
103
106
 
104
- @pydantic.validator("one_qubit_gates")
107
+ @pydantic.field_validator("one_qubit_gates")
108
+ @classmethod
105
109
  def validate_one_qubit_gates(
106
110
  cls, one_qubit_gates: Union[str, List[str]]
107
111
  ) -> Union[str, List[str]]:
@@ -113,7 +117,8 @@ class HardwareEfficientAnsatz(function_params.FunctionParams):
113
117
  raise ClassiqValueError(f"Invalid one qubit gate: {one_qubit_gate}")
114
118
  return one_qubit_gates
115
119
 
116
- @pydantic.validator("two_qubit_gates")
120
+ @pydantic.field_validator("two_qubit_gates")
121
+ @classmethod
117
122
  def validate_two_qubit_gates(
118
123
  cls, two_qubit_gates: Union[str, List[str]]
119
124
  ) -> Union[str, List[str]]:
@@ -14,7 +14,8 @@ from classiq.interface.generator.chemistry_function_params import (
14
14
 
15
15
 
16
16
  class HartreeFock(ChemistryFunctionParams):
17
- @pydantic.validator("gs_problem")
17
+ @pydantic.field_validator("gs_problem")
18
+ @classmethod
18
19
  def validate_gs_problem(
19
20
  cls, gs_problem: Any
20
21
  ) -> Union[MoleculeProblem, HamiltonianProblem]:
@@ -1,6 +1,8 @@
1
1
  from typing import TYPE_CHECKING, List
2
2
 
3
3
  import pydantic
4
+ from pydantic import Field
5
+ from typing_extensions import Annotated
4
6
 
5
7
  from classiq.interface.generator.arith.register_user_input import RegisterUserInput
6
8
  from classiq.interface.generator.function_params import FunctionParams
@@ -8,7 +10,9 @@ from classiq.interface.generator.function_params import FunctionParams
8
10
  if TYPE_CHECKING:
9
11
  NonEmptyRegisterUserInputList = List[RegisterUserInput]
10
12
  else:
11
- NonEmptyRegisterUserInputList = pydantic.conlist(RegisterUserInput, min_items=1)
13
+ NonEmptyRegisterUserInputList = Annotated[
14
+ List[RegisterUserInput], Field(min_length=1)
15
+ ]
12
16
 
13
17
 
14
18
  class Identity(FunctionParams):
@@ -16,7 +20,8 @@ class Identity(FunctionParams):
16
20
  description="registers describing the state (ordered)"
17
21
  )
18
22
 
19
- @pydantic.validator("arguments")
23
+ @pydantic.field_validator("arguments")
24
+ @classmethod
20
25
  def _validate_argument_names(
21
26
  cls, arguments: List[RegisterUserInput]
22
27
  ) -> List[RegisterUserInput]:
@@ -1,6 +1,8 @@
1
- from typing import TYPE_CHECKING, Any, Dict, List
1
+ from typing import TYPE_CHECKING, Any, List
2
2
 
3
3
  import pydantic
4
+ from pydantic import StringConstraints
5
+ from typing_extensions import Annotated, Self
4
6
 
5
7
  from classiq.interface.exceptions import ClassiqValueError
6
8
  from classiq.interface.generator import function_params
@@ -9,15 +11,18 @@ from classiq.interface.generator.arith.register_user_input import RegisterArithm
9
11
  STATE = "state"
10
12
  TARGET = "target"
11
13
 
12
- LENGTH_ERROR_MESSAGE = "Slopes, offsets and basis values must have the same length"
14
+ LENGTH_ERROR_MESSAGE = "Field required"
13
15
 
14
16
  if TYPE_CHECKING:
15
17
  PydanticPauliBasisStr = str
16
18
  else:
17
- PydanticPauliBasisStr = pydantic.constr(
18
- to_lower=True,
19
- regex=r"[xyz]",
20
- )
19
+ PydanticPauliBasisStr = Annotated[
20
+ str,
21
+ StringConstraints(
22
+ to_lower=True,
23
+ pattern=r"[xyz]",
24
+ ),
25
+ ]
21
26
 
22
27
 
23
28
  class LinearPauliRotations(function_params.FunctionParams):
@@ -56,19 +61,27 @@ class LinearPauliRotations(function_params.FunctionParams):
56
61
  description="The offsets of the controlled rotations."
57
62
  )
58
63
 
59
- @pydantic.validator("bases", "slopes", "offsets", pre=True, always=True)
64
+ @pydantic.field_validator("bases", "slopes", "offsets", mode="before")
65
+ @classmethod
60
66
  def as_list(cls, v: Any) -> List[Any]:
61
67
  if not isinstance(v, list):
62
68
  v = [v]
63
- return v
69
+ res = []
70
+ for x in v:
71
+ element = x
72
+ if isinstance(x, str):
73
+ res.append(element.lower())
74
+ else:
75
+ res.append(element)
76
+ return res
64
77
 
65
- @pydantic.root_validator()
66
- def validate_lists(cls, values: Dict[str, Any]) -> Dict[str, Any]:
67
- offsets = values.get("offsets", list())
68
- bases = values.get("bases", list())
69
- slopes = values.get("slopes", list())
78
+ @pydantic.model_validator(mode="after")
79
+ def validate_lists(self) -> Self:
80
+ offsets = self.offsets or list()
81
+ bases = self.bases or list()
82
+ slopes = self.slopes or list()
70
83
  if len(slopes) == len(offsets) and len(offsets) == len(bases):
71
- return values
84
+ return self
72
85
  raise ClassiqValueError(LENGTH_ERROR_MESSAGE)
73
86
 
74
87
  def _create_ios(self) -> None:
@@ -5,8 +5,10 @@ import pydantic
5
5
  from classiq.interface.exceptions import ClassiqValueError
6
6
  from classiq.interface.generator.arith.register_user_input import RegisterUserInput
7
7
  from classiq.interface.generator.control_state import ControlState
8
- from classiq.interface.generator.function_params import FunctionParams
9
- from classiq.interface.generator.parameters import ParameterFloatType
8
+ from classiq.interface.generator.function_params import (
9
+ FunctionParams,
10
+ FunctionParamsNumericParameter,
11
+ )
10
12
 
11
13
  CTRL = "CTRL"
12
14
  TARGET = "TARGET"
@@ -29,17 +31,17 @@ class Mcu(FunctionParams):
29
31
  e^(i*phi)*sin(theta/2) & e^(i*(phi+lam))*cos(theta/2) \\
30
32
  """
31
33
 
32
- theta: ParameterFloatType = pydantic.Field(
33
- default=0, description="Theta radian angle.", is_exec_param=True
34
+ theta: FunctionParamsNumericParameter = pydantic.Field(
35
+ default=0, description="Theta radian angle."
34
36
  )
35
- phi: ParameterFloatType = pydantic.Field(
36
- default=0, description="Phi radian angle.", is_exec_param=True
37
+ phi: FunctionParamsNumericParameter = pydantic.Field(
38
+ default=0, description="Phi radian angle."
37
39
  )
38
- lam: ParameterFloatType = pydantic.Field(
39
- default=0, description="Lambda radian angle.", is_exec_param=True
40
+ lam: FunctionParamsNumericParameter = pydantic.Field(
41
+ default=0, description="Lambda radian angle."
40
42
  )
41
- gam: ParameterFloatType = pydantic.Field(
42
- default=0, description="gam radian angle.", is_exec_param=True
43
+ gam: FunctionParamsNumericParameter = pydantic.Field(
44
+ default=0, description="gam radian angle."
43
45
  )
44
46
 
45
47
  num_ctrl_qubits: Optional[pydantic.PositiveInt] = pydantic.Field(
@@ -49,8 +51,9 @@ class Mcu(FunctionParams):
49
51
  default=None, description="string of the control state"
50
52
  )
51
53
 
52
- @pydantic.root_validator()
53
- def _validate_control(cls, values: Dict[str, Any]) -> Dict[str, Any]:
54
+ @pydantic.model_validator(mode="before")
55
+ @classmethod
56
+ def _validate_control(cls, values: Any) -> Dict[str, Any]:
54
57
  num_ctrl_qubits = values.get("num_ctrl_qubits")
55
58
  ctrl_state = values.get("ctrl_state")
56
59
 
@@ -1,6 +1,7 @@
1
1
  from typing import Any, Dict, List, Optional
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
@@ -20,11 +21,15 @@ class Mcx(FunctionParams):
20
21
  default_factory=list, description="registers describing the state (ordered)"
21
22
  )
22
23
  num_ctrl_qubits: Optional[pydantic.PositiveInt] = pydantic.Field(
23
- description="number of control qubits"
24
+ description="number of control qubits",
25
+ default=None,
26
+ )
27
+ ctrl_state: str = pydantic.Field(
28
+ default="", description="control state string", validate_default=True
24
29
  )
25
- ctrl_state: str = pydantic.Field(default="", description="control state string")
26
30
 
27
- @pydantic.validator("arguments", always=True)
31
+ @pydantic.field_validator("arguments")
32
+ @classmethod
28
33
  def _validate_argument_names(
29
34
  cls, arguments: List[RegisterUserInput]
30
35
  ) -> List[RegisterUserInput]:
@@ -35,10 +40,11 @@ class Mcx(FunctionParams):
35
40
  raise ClassiqValueError("Registers must have distinct names")
36
41
  return arguments
37
42
 
38
- @pydantic.validator("num_ctrl_qubits", always=True)
39
- def _validate_sizes(cls, num_ctrl_qubits: int, values: Dict[str, Any]) -> int:
43
+ @pydantic.model_validator(mode="before")
44
+ @classmethod
45
+ def _validate_sizes(cls, values: Dict[str, Any]) -> Dict[str, Any]:
40
46
  arguments_size = sum(arg.size for arg in values.get("arguments", list()))
41
-
47
+ num_ctrl_qubits = values.get("num_ctrl_qubits")
42
48
  if not num_ctrl_qubits:
43
49
  num_ctrl_qubits = arguments_size - 1
44
50
 
@@ -51,11 +57,13 @@ class Mcx(FunctionParams):
51
57
  values["arguments"] = [ctrl_register, target_register]
52
58
  elif num_ctrl_qubits != arguments_size - 1:
53
59
  raise ClassiqValueError("Given sizes do not match")
54
- return num_ctrl_qubits
60
+ values["num_ctrl_qubits"] = num_ctrl_qubits
61
+ return values
55
62
 
56
- @pydantic.validator("ctrl_state", always=True)
57
- def _validate_ctrl_state(cls, ctrl_state: str, values: Dict[str, Any]) -> str:
58
- num_ctrl_qubits = values.get("num_ctrl_qubits", -1)
63
+ @pydantic.field_validator("ctrl_state")
64
+ @classmethod
65
+ def _validate_ctrl_state(cls, ctrl_state: str, info: ValidationInfo) -> str:
66
+ num_ctrl_qubits = info.data.get("num_ctrl_qubits", -1)
59
67
  if not ctrl_state:
60
68
  return "1" * num_ctrl_qubits
61
69
  if len(ctrl_state) != num_ctrl_qubits:
@@ -2,7 +2,7 @@ from collections import defaultdict
2
2
  from typing import Dict, Optional, Union
3
3
 
4
4
  import pydantic
5
- from pydantic import BaseModel, Extra
5
+ from pydantic import BaseModel, ConfigDict
6
6
 
7
7
  from classiq.interface.enum_utils import StrEnum
8
8
  from classiq.interface.exceptions import ClassiqValueError
@@ -29,7 +29,7 @@ def optimization_parameter_type_from_string(param: str) -> OptimizationParameter
29
29
  raise ClassiqValueError(f"Invalid OptimizationParameterType {param}")
30
30
 
31
31
 
32
- class Constraints(BaseModel, extra=Extra.forbid):
32
+ class Constraints(BaseModel):
33
33
  """
34
34
  Constraints for the quantum circuit synthesis engine.
35
35
 
@@ -51,6 +51,8 @@ class Constraints(BaseModel, extra=Extra.forbid):
51
51
  the solution. Defaults to `NO_OPTIMIZATION`. See `OptimizationParameterType`
52
52
  """
53
53
 
54
+ model_config = ConfigDict(extra="forbid")
55
+
54
56
  max_width: Optional[pydantic.PositiveInt] = pydantic.Field(
55
57
  default=None,
56
58
  description="Maximum number of qubits in generated quantum circuit",
@@ -51,7 +51,8 @@ class ClassiqBaseModel(VersionedModel, ABC):
51
51
  default_factory=ExecutionPreferences
52
52
  )
53
53
 
54
- @pydantic.validator("types")
54
+ @pydantic.field_validator("types")
55
+ @classmethod
55
56
  def types_validator(cls, types: List[StructDeclaration]) -> List[StructDeclaration]:
56
57
  if not is_list_unique([struct_type.name for struct_type in types]):
57
58
  raise ClassiqValueError(TYPE_LIBRARY_DUPLICATED_TYPE_NAMES)