classiq 0.51.1__py3-none-any.whl → 0.52.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (149) hide show
  1. classiq/_internals/api_wrapper.py +41 -15
  2. classiq/_internals/authentication/auth0.py +20 -4
  3. classiq/_internals/authentication/password_manager.py +16 -4
  4. classiq/_internals/client.py +2 -2
  5. classiq/_internals/host_checker.py +5 -3
  6. classiq/_internals/jobs.py +3 -3
  7. classiq/analyzer/analyzer_utilities.py +1 -1
  8. classiq/applications/chemistry/ground_state_problem.py +1 -1
  9. classiq/applications/combinatorial_helpers/pyomo_utils.py +3 -1
  10. classiq/applications/qnn/gradients/quantum_gradient.py +1 -1
  11. classiq/applications/qnn/qlayer.py +2 -2
  12. classiq/execution/__init__.py +3 -0
  13. classiq/execution/execution_session.py +2 -2
  14. classiq/execution/iqcc.py +63 -0
  15. classiq/execution/jobs.py +2 -2
  16. classiq/executor.py +2 -2
  17. classiq/interface/_version.py +1 -1
  18. classiq/interface/analyzer/analysis_params.py +19 -9
  19. classiq/interface/analyzer/cytoscape_graph.py +10 -3
  20. classiq/interface/analyzer/result.py +6 -5
  21. classiq/interface/applications/qsvm.py +13 -12
  22. classiq/interface/backend/backend_preferences.py +78 -105
  23. classiq/interface/backend/ionq/ionq_quantum_program.py +12 -19
  24. classiq/interface/backend/pydantic_backend.py +24 -12
  25. classiq/interface/backend/quantum_backend_providers.py +2 -0
  26. classiq/interface/chemistry/fermionic_operator.py +7 -7
  27. classiq/interface/chemistry/ground_state_problem.py +23 -18
  28. classiq/interface/chemistry/molecule.py +10 -5
  29. classiq/interface/chemistry/operator.py +71 -44
  30. classiq/interface/combinatorial_optimization/mht_qaoa_input.py +2 -1
  31. classiq/interface/debug_info/debug_info.py +3 -4
  32. classiq/interface/execution/iqcc.py +21 -0
  33. classiq/interface/execution/jobs.py +10 -10
  34. classiq/interface/executor/aws_execution_cost.py +37 -20
  35. classiq/interface/executor/execution_preferences.py +1 -2
  36. classiq/interface/executor/execution_request.py +2 -2
  37. classiq/interface/executor/execution_result.py +4 -2
  38. classiq/interface/executor/iqae_result.py +1 -1
  39. classiq/interface/executor/optimizer_preferences.py +14 -10
  40. classiq/interface/executor/quantum_code.py +21 -16
  41. classiq/interface/executor/register_initialization.py +10 -10
  42. classiq/interface/executor/result.py +19 -16
  43. classiq/interface/executor/vqe_result.py +1 -1
  44. classiq/interface/finance/function_input.py +27 -18
  45. classiq/interface/finance/log_normal_model_input.py +2 -2
  46. classiq/interface/finance/model_input.py +3 -2
  47. classiq/interface/generator/amplitude_loading.py +8 -6
  48. classiq/interface/generator/arith/argument_utils.py +24 -0
  49. classiq/interface/generator/arith/arithmetic.py +5 -3
  50. classiq/interface/generator/arith/arithmetic_expression_abc.py +36 -14
  51. classiq/interface/generator/arith/arithmetic_operations.py +6 -3
  52. classiq/interface/generator/arith/binary_ops.py +88 -63
  53. classiq/interface/generator/arith/extremum_operations.py +22 -13
  54. classiq/interface/generator/arith/logical_ops.py +6 -4
  55. classiq/interface/generator/arith/number_utils.py +3 -3
  56. classiq/interface/generator/arith/register_user_input.py +32 -17
  57. classiq/interface/generator/arith/unary_ops.py +5 -4
  58. classiq/interface/generator/chemistry_function_params.py +2 -1
  59. classiq/interface/generator/circuit_code/circuit_code.py +2 -1
  60. classiq/interface/generator/commuting_pauli_exponentiation.py +6 -5
  61. classiq/interface/generator/complex_type.py +14 -18
  62. classiq/interface/generator/control_state.py +32 -26
  63. classiq/interface/generator/expressions/expression.py +6 -5
  64. classiq/interface/generator/function_params.py +22 -39
  65. classiq/interface/generator/functions/classical_function_declaration.py +1 -1
  66. classiq/interface/generator/functions/classical_type.py +32 -23
  67. classiq/interface/generator/functions/concrete_types.py +8 -7
  68. classiq/interface/generator/functions/function_declaration.py +4 -5
  69. classiq/interface/generator/functions/type_name.py +5 -4
  70. classiq/interface/generator/generated_circuit_data.py +9 -6
  71. classiq/interface/generator/grover_diffuser.py +26 -18
  72. classiq/interface/generator/grover_operator.py +32 -22
  73. classiq/interface/generator/hamiltonian_evolution/exponentiation.py +3 -4
  74. classiq/interface/generator/hamiltonian_evolution/qdrift.py +4 -4
  75. classiq/interface/generator/hamiltonian_evolution/suzuki_trotter.py +8 -7
  76. classiq/interface/generator/hardware/hardware_data.py +27 -26
  77. classiq/interface/generator/hardware_efficient_ansatz.py +11 -6
  78. classiq/interface/generator/hartree_fock.py +2 -1
  79. classiq/interface/generator/identity.py +7 -2
  80. classiq/interface/generator/linear_pauli_rotations.py +27 -14
  81. classiq/interface/generator/mcu.py +15 -12
  82. classiq/interface/generator/mcx.py +18 -10
  83. classiq/interface/generator/model/constraints.py +4 -2
  84. classiq/interface/generator/model/model.py +2 -1
  85. classiq/interface/generator/model/preferences/preferences.py +30 -32
  86. classiq/interface/generator/oracles/custom_oracle.py +13 -10
  87. classiq/interface/generator/piecewise_linear_amplitude_loading.py +37 -21
  88. classiq/interface/generator/qpe.py +38 -26
  89. classiq/interface/generator/qsvm.py +4 -4
  90. classiq/interface/generator/quantum_function_call.py +57 -44
  91. classiq/interface/generator/quantum_program.py +8 -6
  92. classiq/interface/generator/range_types.py +10 -11
  93. classiq/interface/generator/standard_gates/controlled_standard_gates.py +9 -5
  94. classiq/interface/generator/standard_gates/standard_angle_metaclass.py +2 -6
  95. classiq/interface/generator/standard_gates/u_gate.py +7 -10
  96. classiq/interface/generator/state_preparation/computational_basis_state_preparation.py +2 -1
  97. classiq/interface/generator/state_preparation/distributions.py +12 -12
  98. classiq/interface/generator/state_preparation/state_preparation.py +22 -16
  99. classiq/interface/generator/types/enum_declaration.py +2 -1
  100. classiq/interface/generator/ucc.py +2 -1
  101. classiq/interface/generator/unitary_gate.py +2 -1
  102. classiq/interface/generator/user_defined_function_params.py +3 -0
  103. classiq/interface/generator/visitor.py +1 -1
  104. classiq/interface/hardware.py +18 -3
  105. classiq/interface/helpers/custom_pydantic_types.py +38 -47
  106. classiq/interface/helpers/pydantic_model_helpers.py +3 -2
  107. classiq/interface/helpers/versioned_model.py +1 -4
  108. classiq/interface/ide/ide_data.py +5 -5
  109. classiq/interface/ide/visual_model.py +5 -5
  110. classiq/interface/interface_version.py +1 -1
  111. classiq/interface/jobs.py +12 -22
  112. classiq/interface/model/bind_operation.py +2 -1
  113. classiq/interface/model/classical_parameter_declaration.py +10 -4
  114. classiq/interface/model/handle_binding.py +20 -24
  115. classiq/interface/model/inplace_binary_operation.py +16 -9
  116. classiq/interface/model/model.py +21 -11
  117. classiq/interface/model/port_declaration.py +10 -7
  118. classiq/interface/model/quantum_expressions/arithmetic_operation.py +6 -4
  119. classiq/interface/model/quantum_function_declaration.py +22 -11
  120. classiq/interface/model/quantum_statement.py +6 -7
  121. classiq/interface/model/quantum_type.py +22 -19
  122. classiq/interface/model/statement_block.py +9 -9
  123. classiq/interface/server/global_versions.py +4 -5
  124. classiq/interface/server/routes.py +8 -0
  125. classiq/model_expansions/evaluators/parameter_types.py +3 -3
  126. classiq/model_expansions/expression_renamer.py +1 -1
  127. classiq/model_expansions/quantum_operations/control.py +11 -12
  128. classiq/model_expansions/quantum_operations/emitter.py +22 -0
  129. classiq/model_expansions/quantum_operations/expression_operation.py +2 -20
  130. classiq/model_expansions/quantum_operations/inplace_binary_operation.py +38 -9
  131. classiq/model_expansions/quantum_operations/invert.py +1 -1
  132. classiq/model_expansions/quantum_operations/phase.py +4 -5
  133. classiq/model_expansions/quantum_operations/power.py +1 -1
  134. classiq/model_expansions/quantum_operations/quantum_assignment_operation.py +50 -9
  135. classiq/model_expansions/quantum_operations/variable_decleration.py +2 -2
  136. classiq/model_expansions/quantum_operations/within_apply.py +1 -1
  137. classiq/qmod/builtins/__init__.py +1 -3
  138. classiq/qmod/builtins/functions/__init__.py +4 -0
  139. classiq/qmod/builtins/functions/arithmetic.py +10 -0
  140. classiq/qmod/create_model_function.py +4 -4
  141. classiq/qmod/quantum_expandable.py +22 -9
  142. classiq/qmod/quantum_function.py +1 -1
  143. classiq/qmod/semantics/static_semantics_visitor.py +3 -1
  144. classiq/qmod/type_attribute_remover.py +1 -1
  145. classiq/qmod/write_qmod.py +2 -4
  146. classiq/synthesis.py +11 -13
  147. {classiq-0.51.1.dist-info → classiq-0.52.0.dist-info}/METADATA +3 -2
  148. {classiq-0.51.1.dist-info → classiq-0.52.0.dist-info}/RECORD +149 -147
  149. {classiq-0.51.1.dist-info → classiq-0.52.0.dist-info}/WHEEL +0 -0
@@ -1,6 +1,7 @@
1
1
  from typing import List, Literal, Union
2
2
 
3
3
  import pydantic
4
+ from pydantic import ConfigDict
4
5
 
5
6
  from classiq.interface.chemistry.elements import ELEMENTS
6
7
  from classiq.interface.exceptions import ClassiqValueError
@@ -20,7 +21,7 @@ class Atom(HashablePydanticBaseModel):
20
21
  class Molecule(HashablePydanticBaseModel):
21
22
  atoms: List[Atom] = pydantic.Field(
22
23
  description="A list of atoms each containing the atoms symbol and its (x,y,z) location",
23
- min_items=1,
24
+ min_length=1,
24
25
  )
25
26
  spin: pydantic.NonNegativeInt = pydantic.Field(
26
27
  default=1, description="spin of the molecule"
@@ -33,12 +34,17 @@ class Molecule(HashablePydanticBaseModel):
33
34
  def atoms_type(self) -> List[AtomType]:
34
35
  return [(atom.symbol, [atom.x, atom.y, atom.z]) for atom in self.atoms]
35
36
 
36
- @pydantic.validator("atoms", each_item=True, pre=True)
37
- def _validate_atoms(cls, atom: Union[AtomType, Atom]) -> Atom:
37
+ @classmethod
38
+ def _validate_atom(cls, atom: Union[AtomType, Atom]) -> Atom:
38
39
  if isinstance(atom, (list, tuple)):
39
40
  return cls._validate_old_atoms_type(atom)
40
41
  return atom
41
42
 
43
+ @pydantic.field_validator("atoms", mode="before")
44
+ @classmethod
45
+ def _validate_atoms(cls, atoms: List[Union[AtomType, Atom]]) -> List[Atom]:
46
+ return [cls._validate_atom(atom) for atom in atoms]
47
+
42
48
  @staticmethod
43
49
  def _validate_old_atoms_type(atom: AtomType) -> Atom:
44
50
  if len(atom) != 2:
@@ -62,5 +68,4 @@ class Molecule(HashablePydanticBaseModel):
62
68
 
63
69
  return Atom(symbol=symbol, x=coordinate[0], y=coordinate[1], z=coordinate[2])
64
70
 
65
- class Config:
66
- frozen = True
71
+ model_config = ConfigDict(frozen=True)
@@ -5,7 +5,6 @@ from typing import (
5
5
  Dict,
6
6
  List,
7
7
  Optional,
8
- Tuple,
9
8
  Union,
10
9
  cast,
11
10
  )
@@ -14,6 +13,7 @@ import numpy as np
14
13
  import pydantic
15
14
  import sympy
16
15
  from more_itertools import all_equal
16
+ from pydantic import ConfigDict
17
17
 
18
18
  from classiq.interface.exceptions import ClassiqValueError
19
19
  from classiq.interface.generator.function_params import validate_expression_str
@@ -42,8 +42,8 @@ class PauliOperator(HashablePydanticBaseModel, VersionedModel):
42
42
  pauli_list: PydanticPauliList = pydantic.Field(
43
43
  description="A list of tuples each containing a pauli string comprised of I,X,Y,Z characters and a complex coefficient; for example [('IZ', 0.1), ('XY', 0.2)].",
44
44
  )
45
- is_hermitian: bool = pydantic.Field(default=False)
46
45
  has_complex_coefficients: bool = pydantic.Field(default=True)
46
+ is_hermitian: bool = pydantic.Field(default=False)
47
47
 
48
48
  def show(self) -> str:
49
49
  if self.is_hermitian:
@@ -55,16 +55,19 @@ class PauliOperator(HashablePydanticBaseModel, VersionedModel):
55
55
  f"+({summand[1]:+.3f}) * {summand[0]}" for summand in self.pauli_list
56
56
  )
57
57
 
58
- @pydantic.validator("pauli_list", each_item=True, pre=True)
58
+ @pydantic.field_validator("pauli_list", mode="before")
59
+ @classmethod
59
60
  def _validate_pauli_monomials(
60
- cls, monomial: Tuple[PydanticPauliMonomialStr, ParameterComplexType]
61
- ) -> Tuple[PydanticPauliMonomialStr, ParameterComplexType]:
62
- _PauliMonomialLengthValidator( # type: ignore[call-arg]
63
- monomial=monomial
64
- ) # Validate the length of the monomial.
65
- coeff = cls._validate_monomial_coefficient(monomial[1])
66
- parsed_monomial = _PauliMonomialParser(string=monomial[0], coeff=coeff) # type: ignore[call-arg]
67
- return (parsed_monomial.string, parsed_monomial.coeff)
61
+ cls, pauli_list: PydanticPauliList
62
+ ) -> PydanticPauliList:
63
+ validated_pauli_list = []
64
+ for monomial in pauli_list:
65
+ # Validate the length
66
+ _PauliMonomialLengthValidator(monomial=monomial) # type: ignore[call-arg]
67
+ coeff = cls._validate_monomial_coefficient(monomial[1])
68
+ parsed_monomial = _PauliMonomialParser(string=monomial[0], coeff=coeff)
69
+ validated_pauli_list.append((parsed_monomial.string, parsed_monomial.coeff))
70
+ return validated_pauli_list
68
71
 
69
72
  @staticmethod
70
73
  def _validate_monomial_coefficient(
@@ -76,16 +79,38 @@ class PauliOperator(HashablePydanticBaseModel, VersionedModel):
76
79
  coeff = str(coeff)
77
80
  return coeff
78
81
 
79
- @pydantic.validator("pauli_list")
82
+ @pydantic.field_validator("pauli_list", mode="after")
83
+ @classmethod
80
84
  def _validate_pauli_list(cls, pauli_list: PydanticPauliList) -> PydanticPauliList:
81
85
  if not all_equal(len(summand[0]) for summand in pauli_list):
82
86
  raise ClassiqValueError("Pauli strings have incompatible lengths.")
83
87
  return pauli_list
84
88
 
85
- @pydantic.root_validator
89
+ @staticmethod
90
+ def check_if_hermitian(pauli_list: PydanticPauliList) -> bool:
91
+ if all(isinstance(summand[1], (float, int, complex)) for summand in pauli_list):
92
+ if all(np.isclose(summand[1].imag, 0) for summand in pauli_list): # type: ignore[union-attr]
93
+ return True
94
+
95
+ for pauli_string, coeff in pauli_list:
96
+ reverse_string = pauli_string[::-1]
97
+ reverse_found = False
98
+ for other_string, other_coeff in pauli_list:
99
+ if other_string == reverse_string and np.isclose(
100
+ coeff, other_coeff.conjugate() # type: ignore[union-attr]
101
+ ):
102
+ reverse_found = True
103
+ break
104
+ if not reverse_found:
105
+ return False
106
+ return True
107
+ return False
108
+
109
+ @pydantic.model_validator(mode="before")
110
+ @classmethod
86
111
  def _validate_hermitianity(cls, values: Dict[str, Any]) -> Dict[str, Any]:
87
112
  pauli_list = values.get("pauli_list", [])
88
- if all(isinstance(summand[1], complex) for summand in pauli_list):
113
+ if PauliOperator.check_if_hermitian(pauli_list):
89
114
  values["is_hermitian"] = all(
90
115
  np.isclose(complex(summand[1]).real, summand[1])
91
116
  for summand in pauli_list
@@ -93,7 +118,7 @@ class PauliOperator(HashablePydanticBaseModel, VersionedModel):
93
118
  if values.get("is_hermitian", False):
94
119
  values["has_complex_coefficients"] = False
95
120
  values["pauli_list"] = [
96
- (summand[0], complex(summand[1].real)) for summand in pauli_list
121
+ (summand[0], complex(summand[1]).real) for summand in pauli_list
97
122
  ]
98
123
  else:
99
124
  values["has_complex_coefficients"] = not all(
@@ -161,7 +186,7 @@ class PauliOperator(HashablePydanticBaseModel, VersionedModel):
161
186
  (self._extend_pauli_string(pauli_string, num_extra_qubits), coeff)
162
187
  for (pauli_string, coeff) in self.pauli_list
163
188
  ]
164
- return self.copy(update={"pauli_list": new_pauli_list}, deep=True)
189
+ return self.model_copy(update={"pauli_list": new_pauli_list}, deep=True)
165
190
 
166
191
  @staticmethod
167
192
  def _reorder_pauli_string(
@@ -211,7 +236,7 @@ class PauliOperator(HashablePydanticBaseModel, VersionedModel):
211
236
  (cls._reorder_pauli_string(pauli_string, order, new_num_qubits), coeff)
212
237
  for pauli_string, coeff in operator.pauli_list
213
238
  ]
214
- return cls(pauli_list=new_pauli_list)
239
+ return cls(pauli_list=new_pauli_list, is_hermitian=operator.is_hermitian)
215
240
 
216
241
  @classmethod
217
242
  def from_unzipped_lists(
@@ -234,8 +259,7 @@ class PauliOperator(HashablePydanticBaseModel, VersionedModel):
234
259
  ]
235
260
  )
236
261
 
237
- class Config:
238
- frozen = True
262
+ model_config = ConfigDict(frozen=True)
239
263
 
240
264
 
241
265
  class PauliOperatorV1(HashablePydanticBaseModel):
@@ -259,16 +283,19 @@ class PauliOperatorV1(HashablePydanticBaseModel):
259
283
  f"+({summand[1]:+.3f}) * {summand[0]}" for summand in self.pauli_list
260
284
  )
261
285
 
262
- @pydantic.validator("pauli_list", each_item=True, pre=True)
286
+ @pydantic.field_validator("pauli_list", mode="before")
287
+ @classmethod
263
288
  def _validate_pauli_monomials(
264
- cls, monomial: Tuple[PydanticPauliMonomialStr, ParameterComplexType]
265
- ) -> Tuple[PydanticPauliMonomialStr, ParameterComplexType]:
266
- _PauliMonomialLengthValidator( # type: ignore[call-arg]
267
- monomial=monomial
268
- ) # Validate the length of the monomial.
269
- coeff = cls._validate_monomial_coefficient(monomial[1])
270
- parsed_monomial = _PauliMonomialParser(string=monomial[0], coeff=coeff) # type: ignore[call-arg]
271
- return (parsed_monomial.string, parsed_monomial.coeff)
289
+ cls, pauli_list: PydanticPauliList
290
+ ) -> PydanticPauliList:
291
+ validated_pauli_list = []
292
+ for monomial in pauli_list:
293
+ # Validate the length
294
+ _PauliMonomialLengthValidator(monomial=monomial) # type: ignore[call-arg]
295
+ coeff = cls._validate_monomial_coefficient(monomial[1])
296
+ parsed_monomial = _PauliMonomialParser(string=monomial[0], coeff=coeff)
297
+ validated_pauli_list.append((parsed_monomial.string, parsed_monomial.coeff))
298
+ return validated_pauli_list
272
299
 
273
300
  @staticmethod
274
301
  def _validate_monomial_coefficient(
@@ -280,32 +307,34 @@ class PauliOperatorV1(HashablePydanticBaseModel):
280
307
  coeff = str(coeff)
281
308
  return coeff
282
309
 
283
- @pydantic.validator("pauli_list")
310
+ @pydantic.field_validator("pauli_list", mode="after")
311
+ @classmethod
284
312
  def _validate_pauli_list(cls, pauli_list: PydanticPauliList) -> PydanticPauliList:
285
313
  if not all_equal(len(summand[0]) for summand in pauli_list):
286
314
  raise ClassiqValueError("Pauli strings have incompatible lengths.")
287
315
  return pauli_list
288
316
 
289
- @pydantic.root_validator
290
- def _validate_hermitianity(cls, values: Dict[str, Any]) -> Dict[str, Any]:
291
- pauli_list = values.get("pauli_list", [])
317
+ @pydantic.model_validator(mode="before")
318
+ @classmethod
319
+ def _validate_hermitianity(cls, v: Dict[str, Any]) -> Dict[str, Any]:
320
+ pauli_list = cast(PydanticPauliList, v.get("pauli_list"))
292
321
  if all(isinstance(summand[1], complex) for summand in pauli_list):
293
- values["is_hermitian"] = all(
322
+ v["is_hermitian"] = all(
294
323
  np.isclose(complex(summand[1]).real, summand[1])
295
324
  for summand in pauli_list
296
325
  )
297
- if values.get("is_hermitian", False):
298
- values["has_complex_coefficients"] = False
299
- values["pauli_list"] = [
300
- (summand[0], complex(summand[1].real)) for summand in pauli_list
326
+ if v["is_hermitian"]:
327
+ v["has_complex_coefficients"] = False
328
+ v["pauli_list"] = [
329
+ (summand[0], complex(summand[1]).real) for summand in pauli_list
301
330
  ]
302
331
  else:
303
- values["has_complex_coefficients"] = not all(
332
+ v["has_complex_coefficients"] = not all(
304
333
  np.isclose(complex(summand[1]).real, summand[1])
305
334
  for summand in pauli_list
306
335
  if isinstance(summand[1], complex)
307
336
  )
308
- return values
337
+ return v
309
338
 
310
339
  def __mul__(self, coefficient: complex) -> "PauliOperatorV1":
311
340
  multiplied_ising = [
@@ -361,7 +390,7 @@ class PauliOperatorV1(HashablePydanticBaseModel):
361
390
  (self._extend_pauli_string(pauli_string, num_extra_qubits), coeff)
362
391
  for (pauli_string, coeff) in self.pauli_list
363
392
  ]
364
- return self.copy(update={"pauli_list": new_pauli_list}, deep=True)
393
+ return self.model_copy(update={"pauli_list": new_pauli_list}, deep=True)
365
394
 
366
395
  @staticmethod
367
396
  def _reorder_pauli_string(
@@ -434,8 +463,7 @@ class PauliOperatorV1(HashablePydanticBaseModel):
434
463
  ]
435
464
  )
436
465
 
437
- class Config:
438
- frozen = True
466
+ model_config = ConfigDict(frozen=True)
439
467
 
440
468
 
441
469
  # This class validates the length of a monomial.
@@ -444,8 +472,7 @@ class _PauliMonomialLengthValidator:
444
472
  monomial: PydanticPauliMonomial
445
473
 
446
474
 
447
- @pydantic.dataclasses.dataclass
448
- class _PauliMonomialParser:
475
+ class _PauliMonomialParser(pydantic.BaseModel):
449
476
  string: PydanticPauliMonomialStr
450
477
  coeff: PydanticParameterComplexType
451
478
 
@@ -53,7 +53,8 @@ class MhtQaoaInput(BaseModel):
53
53
  def is_valid_cost(self, cost: float) -> bool:
54
54
  return True
55
55
 
56
- @pydantic.validator("plot_list")
56
+ @pydantic.field_validator("plot_list")
57
+ @classmethod
57
58
  def round_plot_list_times_and_validate(
58
59
  cls, plot_list: List[PlotData]
59
60
  ) -> List[PlotData]:
@@ -15,8 +15,7 @@ ParameterValue = Union[float, int, str, None]
15
15
  class FunctionDebugInfo(BaseModel):
16
16
  name: str
17
17
  # Parameters describe classical parameters passed to function
18
- # ParameterValue appears in type only for backwards compatibility
19
- parameters: Dict[str, str] = Field(type=Dict[str, ParameterValue])
18
+ parameters: Dict[str, str]
20
19
  level: OperationLevel
21
20
  is_allocate_or_free: bool = Field(default=False)
22
21
  is_inverse: bool = Field(default=False)
@@ -54,8 +53,8 @@ class DebugInfoCollection(BaseModel):
54
53
  # Pydantic only started supporting UUID as keys in Pydantic V2
55
54
  # See https://github.com/pydantic/pydantic/issues/2096#issuecomment-814860206
56
55
  # For now, we use strings as keys in the raw data and use UUID in the wrapper logic
57
- data: Dict[str, FunctionDebugInfo] = Field(default_factory=dict)
58
- blackbox_data: Dict[str, FunctionDebugInfoInterface] = Field(default_factory=dict)
56
+ data: Dict[str, FunctionDebugInfo] = Field(default={})
57
+ blackbox_data: Dict[str, FunctionDebugInfoInterface] = Field(default={})
59
58
 
60
59
  def __setitem__(self, key: UUID, value: FunctionDebugInfo) -> None:
61
60
  self.data[str(key)] = value
@@ -0,0 +1,21 @@
1
+ from typing import Optional
2
+
3
+ from classiq.interface.helpers.versioned_model import VersionedModel
4
+
5
+
6
+ class IQCCInitAuthData(VersionedModel):
7
+ auth_scope_id: str
8
+ auth_method_id: str
9
+
10
+
11
+ class IQCCInitAuthResponse(VersionedModel):
12
+ auth_url: str
13
+ token_id: str
14
+
15
+
16
+ class IQCCProbeAuthData(IQCCInitAuthData):
17
+ token_id: str
18
+
19
+
20
+ class IQCCProbeAuthResponse(VersionedModel):
21
+ auth_token: Optional[str]
@@ -1,28 +1,28 @@
1
1
  from datetime import datetime
2
2
  from typing import List, Optional
3
3
 
4
- from pydantic import BaseModel, Extra
4
+ from pydantic import BaseModel
5
5
 
6
6
  from classiq.interface.jobs import JobStatus
7
7
 
8
8
 
9
- class ExecutionJobDetailsV1(BaseModel, extra=Extra.ignore):
9
+ class ExecutionJobDetailsV1(BaseModel, extra="ignore"):
10
10
  id: str
11
11
 
12
- name: Optional[str]
12
+ name: Optional[str] = None
13
13
  start_time: datetime
14
- end_time: Optional[datetime]
14
+ end_time: Optional[datetime] = None
15
15
 
16
- provider: Optional[str]
17
- backend_name: Optional[str]
16
+ provider: Optional[str] = None
17
+ backend_name: Optional[str] = None
18
18
 
19
19
  status: JobStatus
20
20
 
21
- num_shots: Optional[int]
22
- program_id: Optional[str]
21
+ num_shots: Optional[int] = None
22
+ program_id: Optional[str] = None
23
23
 
24
- error: Optional[str]
24
+ error: Optional[str] = None
25
25
 
26
26
 
27
- class ExecutionJobsQueryResultsV1(BaseModel, extra=Extra.ignore):
27
+ class ExecutionJobsQueryResultsV1(BaseModel, extra="ignore"):
28
28
  results: List[ExecutionJobDetailsV1]
@@ -1,11 +1,12 @@
1
+ import datetime
1
2
  from datetime import date
2
- from typing import Any, Dict, List, Optional
3
+ from typing import Any, Dict, List, Optional, Union
3
4
 
4
5
  import pydantic
5
- from pydantic import validator
6
+ from pydantic import BaseModel, ConfigDict, Field
7
+ from pydantic_core.core_schema import ValidationInfo
6
8
 
7
9
  from classiq.interface.enum_utils import StrEnum
8
- from classiq.interface.exceptions import ClassiqValueError
9
10
 
10
11
 
11
12
  class Granularity(StrEnum):
@@ -19,30 +20,44 @@ class CostScope(StrEnum):
19
20
  organization = "organization"
20
21
 
21
22
 
22
- class ExecutionCostForTimePeriod(pydantic.BaseModel):
23
- start: date = pydantic.Field(
24
- description="The beginning of the time period for tasks usage and cost ("
25
- "inclusive).",
23
+ class ExecutionCostForTimePeriod(BaseModel):
24
+ start: date = Field(
25
+ description="The beginning of the time period for tasks usage and cost (inclusive)."
26
26
  )
27
- end: date = pydantic.Field(
28
- description="The end of the time period for tasks usage and cost (exclusive).",
27
+ end: date = Field(
28
+ description="The end of the time period for tasks usage and cost (exclusive)."
29
29
  )
30
- granularity: Granularity = pydantic.Field(
30
+ granularity: Granularity = Field(
31
31
  description="Either MONTHLY or DAILY, or HOURLY.", default=Granularity.daily
32
32
  )
33
- cost_scope: CostScope = pydantic.Field(
33
+ cost_scope: CostScope = Field(
34
34
  description="Either user or organization", default=CostScope.user
35
35
  )
36
36
 
37
- class Config:
38
- json_encoders = {date: lambda v: v.strftime("%Y-%m-%d")}
39
-
40
- @validator("end")
41
- def date_order(cls, v: date, values: Dict[str, Any], **kwargs: Any) -> date:
42
- if "start" in values and v <= values["start"]:
43
- raise ClassiqValueError('"end" date should be after "start" date')
37
+ @pydantic.field_validator("start", mode="before")
38
+ @classmethod
39
+ def validate_start_date(cls, start_date: Union[datetime.datetime, date]) -> date:
40
+ if isinstance(start_date, datetime.datetime):
41
+ return start_date.date()
42
+ return start_date
43
+
44
+ @pydantic.field_validator("end", mode="before")
45
+ @classmethod
46
+ def validate_date_and_date_order(
47
+ cls, v: Union[date, datetime.datetime], info: ValidationInfo
48
+ ) -> date:
49
+ if isinstance(v, datetime.datetime):
50
+ v = v.date()
51
+ if "start" in info.data and v <= info.data["start"]:
52
+ raise ValueError('"end" date should be after "start" date')
44
53
  return v
45
54
 
55
+ def dict(self, **kwargs: Any) -> Dict[str, Any]:
56
+ data = super().model_dump(**kwargs)
57
+ data["start"] = self.start.strftime("%Y-%m-%d")
58
+ data["end"] = self.end.strftime("%Y-%m-%d")
59
+ return data
60
+
46
61
 
47
62
  """The following models describe the aws response model and based on this schema:
48
63
  https://boto3.amazonaws.com/v1/documentation/api/latest/reference/services/ce.html#CostExplorer.Client.get_cost_and_usage"""
@@ -65,8 +80,10 @@ class Total(pydantic.BaseModel):
65
80
  class ExecutedTaskForPeriodItem(pydantic.BaseModel):
66
81
  TimePeriod: TimePeriod
67
82
  Total: Total
68
- Groups: Optional[List]
69
- Estimated: Optional[bool]
83
+ Groups: Optional[List] = None
84
+ Estimated: Optional[bool] = None
85
+
86
+ model_config = ConfigDict(extra="forbid")
70
87
 
71
88
 
72
89
  class ExecutionCostForTimePeriodResponse(pydantic.BaseModel):
@@ -59,8 +59,7 @@ class ExecutionPreferences(pydantic.BaseModel):
59
59
  title="Transpilation Option",
60
60
  )
61
61
  job_name: Optional[str] = pydantic.Field(
62
- min_length=1,
63
- description="The job name",
62
+ min_length=1, description="The job name", default=None
64
63
  )
65
64
 
66
65
 
@@ -57,9 +57,9 @@ class ExecutionJobDetails(VersionedModel):
57
57
  status: JobStatus
58
58
 
59
59
  num_shots: Optional[int]
60
- program_id: Optional[str]
60
+ program_id: Optional[str] = Field(default=None)
61
61
 
62
- error: Optional[str]
62
+ error: Optional[str] = Field(default=None)
63
63
 
64
64
 
65
65
  class ExecutionJobsQueryResults(VersionedModel):
@@ -1,6 +1,6 @@
1
1
  from typing import Any, List, Literal, Union
2
2
 
3
- from pydantic import BaseModel, Field
3
+ from pydantic import BaseModel, ConfigDict, Field
4
4
  from typing_extensions import Annotated, TypeAlias
5
5
 
6
6
  from classiq.interface.enum_utils import StrEnum
@@ -85,7 +85,7 @@ class TaggedIQAEResult(BaseModel):
85
85
  class TaggedUnstructured(BaseModel):
86
86
  value_type: Literal[SavedResultValueType.Unstructured]
87
87
  name: str
88
- value: Any
88
+ value: Any = None
89
89
 
90
90
 
91
91
  SavedResult = Annotated[
@@ -109,3 +109,5 @@ ResultsCollection: TypeAlias = List[SavedResult]
109
109
 
110
110
  class ExecuteGeneratedCircuitResults(VersionedModel):
111
111
  results: ResultsCollection
112
+
113
+ model_config = ConfigDict(extra="forbid")
@@ -14,6 +14,6 @@ class IQAEIterationData(BaseModel):
14
14
 
15
15
  class IQAEResult(VersionedModel, QmodPyObject):
16
16
  estimation: float
17
- confidence_interval: List[float] = Field(min_items=2, max_items=2)
17
+ confidence_interval: List[float] = Field(min_length=2, max_length=2)
18
18
  iterations_data: List[IQAEIterationData]
19
19
  warnings: List[str]
@@ -1,7 +1,8 @@
1
- from typing import Any, Dict, List, Optional
1
+ from typing import List, Optional
2
2
 
3
3
  import pydantic
4
4
  from pydantic import BaseModel
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
@@ -53,11 +54,12 @@ class OptimizerPreferences(BaseModel):
53
54
  description="If True, the optimizer will not compute the variance of the ansatz.",
54
55
  )
55
56
 
56
- @pydantic.validator("tolerance", pre=True, always=True)
57
+ @pydantic.field_validator("tolerance", mode="before")
58
+ @classmethod
57
59
  def check_tolerance(
58
- cls, tolerance: Optional[pydantic.PositiveFloat], values: Dict[str, Any]
60
+ cls, tolerance: Optional[pydantic.PositiveFloat], info: ValidationInfo
59
61
  ) -> Optional[pydantic.PositiveFloat]:
60
- optimizer_type = values.get("type")
62
+ optimizer_type = info.data.get("type")
61
63
  if tolerance is not None and optimizer_type == OptimizerType.SPSA:
62
64
  raise ClassiqValueError("No tolerance param for SPSA optimizer")
63
65
 
@@ -66,11 +68,12 @@ class OptimizerPreferences(BaseModel):
66
68
 
67
69
  return tolerance
68
70
 
69
- @pydantic.validator("step_size", pre=True, always=True)
71
+ @pydantic.field_validator("step_size", mode="before")
72
+ @classmethod
70
73
  def check_step_size(
71
- cls, step_size: Optional[pydantic.PositiveFloat], values: Dict[str, Any]
74
+ cls, step_size: Optional[pydantic.PositiveFloat], info: ValidationInfo
72
75
  ) -> Optional[pydantic.PositiveFloat]:
73
- optimizer_type = values.get("name")
76
+ optimizer_type = info.data.get("name")
74
77
  if step_size is not None and optimizer_type not in (
75
78
  OptimizerType.L_BFGS_B,
76
79
  OptimizerType.ADAM,
@@ -109,11 +112,12 @@ class CombinatorialOptimizer(OptimizerPreferences):
109
112
  description="Whether to check if all the solutions satisfy the constraints",
110
113
  )
111
114
 
112
- @pydantic.validator("alpha_cvar", pre=True, always=True)
115
+ @pydantic.field_validator("alpha_cvar", mode="before")
116
+ @classmethod
113
117
  def check_alpha_cvar(
114
- cls, alpha_cvar: Optional[PydanticAlphaParamCVAR], values: Dict[str, Any]
118
+ cls, alpha_cvar: Optional[PydanticAlphaParamCVAR], info: ValidationInfo
115
119
  ) -> Optional[PydanticAlphaParamCVAR]:
116
- cost_type = values.get("cost_type")
120
+ cost_type = info.data.get("cost_type")
117
121
  if alpha_cvar is not None and cost_type != CostType.CVAR:
118
122
  raise ClassiqValueError("Use CVAR params only for CostType.CVAR.")
119
123
 
@@ -4,7 +4,8 @@ from pathlib import Path
4
4
  from typing import Any, Dict, Optional, Tuple, Union
5
5
 
6
6
  import pydantic
7
- from pydantic import BaseModel
7
+ from pydantic import BaseModel, ConfigDict
8
+ from pydantic_core.core_schema import ValidationInfo
8
9
 
9
10
  from classiq.interface.backend.ionq.ionq_quantum_program import IonqQuantumCircuit
10
11
  from classiq.interface.backend.pydantic_backend import PydanticArgumentNameType
@@ -31,17 +32,18 @@ class QuantumBaseCode(BaseModel):
31
32
  ..., description="The textual representation of the program"
32
33
  )
33
34
 
34
- @pydantic.validator("code")
35
+ @pydantic.field_validator("code")
36
+ @classmethod
35
37
  def load_quantum_program(
36
- cls, code: Union[CodeType, IonqQuantumCircuit], values: Dict[str, Any]
38
+ cls, code: Union[CodeType, IonqQuantumCircuit], values: ValidationInfo
37
39
  ) -> CodeType:
38
- syntax = values.get("syntax")
40
+ syntax = values.data.get("syntax")
39
41
  if isinstance(code, IonqQuantumCircuit):
40
42
  if syntax != QuantumInstructionSet.IONQ:
41
43
  raise ClassiqValueError(
42
44
  f"Invalid code type {type(code)} for syntax: {syntax}"
43
45
  )
44
- return code.json()
46
+ return code.model_dump_json()
45
47
 
46
48
  return code
47
49
 
@@ -56,41 +58,44 @@ class QuantumCode(QuantumBaseCode):
56
58
  description="The map of outputs to their qubits in the circuit.",
57
59
  )
58
60
  registers_initialization: Optional[RegistersInitialization] = pydantic.Field(
59
- default_factory=None,
61
+ default=None,
60
62
  description="Initial conditions for the different registers in the circuit.",
61
63
  )
62
64
  synthesis_execution_data: Optional[ExecutionData] = pydantic.Field(default=None)
63
65
  synthesis_execution_arguments: Arguments = pydantic.Field(default_factory=dict)
66
+ model_config = ConfigDict(validate_assignment=True)
64
67
 
65
- class Config:
66
- validate_assignment = True
67
-
68
- @pydantic.validator("arguments")
68
+ @pydantic.field_validator("arguments", mode="before")
69
+ @classmethod
69
70
  def validate_arguments(
70
- cls, arguments: MultipleArguments, values: Dict[str, Any]
71
+ cls, arguments: MultipleArguments, info: ValidationInfo
71
72
  ) -> MultipleArguments:
72
- if arguments and values.get("syntax") not in (
73
+ if arguments and info.data.get("syntax") not in (
73
74
  QuantumInstructionSet.QSHARP,
74
75
  QuantumInstructionSet.QASM,
75
76
  ):
76
77
  raise ClassiqValueError("Only QASM or Q# programs support arguments")
77
78
 
78
- if values.get("syntax") == QuantumInstructionSet.QSHARP and len(arguments) > 1:
79
+ if (
80
+ info.data.get("syntax") == QuantumInstructionSet.QSHARP
81
+ and len(arguments) > 1
82
+ ):
79
83
  raise ClassiqValueError(
80
84
  f"Q# programs supports only one group of arguments. {len(arguments)} given"
81
85
  )
82
86
 
83
87
  return arguments
84
88
 
85
- @pydantic.validator("synthesis_execution_data")
89
+ @pydantic.field_validator("synthesis_execution_data")
90
+ @classmethod
86
91
  def validate_synthesis_execution_data(
87
92
  cls,
88
93
  synthesis_execution_data: Optional[ExecutionData],
89
- values: Dict[str, Any],
94
+ values: ValidationInfo,
90
95
  ) -> Optional[ExecutionData]:
91
96
  if (
92
97
  synthesis_execution_data is not None
93
- and values.get("syntax") is not QuantumInstructionSet.QASM
98
+ and values.data.get("syntax") is not QuantumInstructionSet.QASM
94
99
  ):
95
100
  raise ClassiqValueError("Only QASM supports the requested configuration")
96
101