classiq 0.83.0__py3-none-any.whl → 0.85.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 (103) hide show
  1. classiq/_internals/api_wrapper.py +27 -0
  2. classiq/applications/chemistry/chemistry_model_constructor.py +0 -2
  3. classiq/applications/chemistry/hartree_fock.py +68 -0
  4. classiq/applications/chemistry/mapping.py +85 -0
  5. classiq/applications/chemistry/op_utils.py +79 -0
  6. classiq/applications/chemistry/problems.py +195 -0
  7. classiq/applications/chemistry/ucc.py +109 -0
  8. classiq/applications/chemistry/z2_symmetries.py +368 -0
  9. classiq/applications/combinatorial_helpers/pauli_helpers/pauli_utils.py +30 -1
  10. classiq/applications/combinatorial_optimization/combinatorial_problem.py +20 -42
  11. classiq/{model_expansions/evaluators → evaluators}/arg_type_match.py +12 -4
  12. classiq/{model_expansions/evaluators → evaluators}/argument_types.py +1 -1
  13. classiq/evaluators/classical_expression.py +53 -0
  14. classiq/{model_expansions/evaluators → evaluators}/classical_type_inference.py +3 -4
  15. classiq/{model_expansions/evaluators → evaluators}/parameter_types.py +17 -15
  16. classiq/execution/__init__.py +12 -1
  17. classiq/execution/execution_session.py +238 -49
  18. classiq/execution/jobs.py +26 -1
  19. classiq/execution/qnn.py +2 -2
  20. classiq/execution/user_budgets.py +39 -0
  21. classiq/interface/_version.py +1 -1
  22. classiq/interface/constants.py +1 -0
  23. classiq/interface/debug_info/debug_info.py +0 -4
  24. classiq/interface/execution/primitives.py +29 -1
  25. classiq/interface/executor/estimate_cost.py +35 -0
  26. classiq/interface/executor/execution_result.py +13 -0
  27. classiq/interface/executor/result.py +116 -1
  28. classiq/interface/executor/user_budget.py +26 -33
  29. classiq/interface/generator/expressions/atomic_expression_functions.py +10 -1
  30. classiq/interface/generator/expressions/proxies/classical/any_classical_value.py +0 -6
  31. classiq/interface/generator/functions/builtins/internal_operators.py +2 -0
  32. classiq/interface/generator/functions/classical_type.py +2 -35
  33. classiq/interface/generator/functions/concrete_types.py +20 -3
  34. classiq/interface/generator/functions/type_modifier.py +0 -19
  35. classiq/interface/generator/generated_circuit_data.py +5 -18
  36. classiq/interface/generator/types/compilation_metadata.py +0 -3
  37. classiq/interface/ide/operation_registry.py +45 -0
  38. classiq/interface/ide/visual_model.py +68 -3
  39. classiq/interface/model/bounds.py +12 -2
  40. classiq/interface/model/model.py +12 -7
  41. classiq/interface/model/port_declaration.py +2 -24
  42. classiq/interface/model/quantum_expressions/arithmetic_operation.py +7 -4
  43. classiq/interface/model/variable_declaration_statement.py +33 -6
  44. classiq/interface/pretty_print/__init__.py +0 -0
  45. classiq/{qmod/native → interface/pretty_print}/expression_to_qmod.py +18 -11
  46. classiq/interface/server/routes.py +4 -0
  47. classiq/model_expansions/atomic_expression_functions_defs.py +47 -6
  48. classiq/model_expansions/function_builder.py +4 -1
  49. classiq/model_expansions/interpreters/base_interpreter.py +3 -3
  50. classiq/model_expansions/interpreters/generative_interpreter.py +16 -1
  51. classiq/model_expansions/quantum_operations/allocate.py +1 -1
  52. classiq/model_expansions/quantum_operations/assignment_result_processor.py +64 -22
  53. classiq/model_expansions/quantum_operations/bind.py +2 -2
  54. classiq/model_expansions/quantum_operations/bounds.py +7 -1
  55. classiq/model_expansions/quantum_operations/call_emitter.py +26 -20
  56. classiq/model_expansions/quantum_operations/classical_var_emitter.py +16 -0
  57. classiq/model_expansions/quantum_operations/variable_decleration.py +31 -11
  58. classiq/model_expansions/scope.py +7 -0
  59. classiq/model_expansions/scope_initialization.py +3 -3
  60. classiq/model_expansions/transformers/model_renamer.py +6 -4
  61. classiq/model_expansions/transformers/type_modifier_inference.py +81 -43
  62. classiq/model_expansions/transformers/var_splitter.py +1 -1
  63. classiq/model_expansions/visitors/symbolic_param_inference.py +2 -3
  64. classiq/open_library/functions/__init__.py +3 -2
  65. classiq/open_library/functions/amplitude_amplification.py +10 -18
  66. classiq/open_library/functions/discrete_sine_cosine_transform.py +5 -5
  67. classiq/open_library/functions/grover.py +14 -6
  68. classiq/open_library/functions/modular_exponentiation.py +22 -20
  69. classiq/open_library/functions/qaoa_penalty.py +8 -1
  70. classiq/open_library/functions/state_preparation.py +18 -32
  71. classiq/qmod/__init__.py +2 -0
  72. classiq/qmod/builtins/enums.py +23 -0
  73. classiq/qmod/builtins/functions/__init__.py +2 -0
  74. classiq/qmod/builtins/functions/exponentiation.py +32 -4
  75. classiq/qmod/builtins/operations.py +65 -1
  76. classiq/qmod/builtins/structs.py +55 -3
  77. classiq/qmod/classical_variable.py +74 -0
  78. classiq/qmod/declaration_inferrer.py +3 -2
  79. classiq/qmod/native/pretty_printer.py +20 -20
  80. classiq/qmod/pretty_print/expression_to_python.py +2 -1
  81. classiq/qmod/pretty_print/pretty_printer.py +35 -21
  82. classiq/qmod/python_classical_type.py +12 -5
  83. classiq/qmod/qfunc.py +2 -19
  84. classiq/qmod/qmod_constant.py +2 -5
  85. classiq/qmod/qmod_parameter.py +2 -5
  86. classiq/qmod/qmod_variable.py +61 -23
  87. classiq/qmod/quantum_expandable.py +5 -3
  88. classiq/qmod/quantum_function.py +49 -4
  89. classiq/qmod/semantics/annotation/qstruct_annotator.py +1 -1
  90. classiq/qmod/semantics/validation/main_validation.py +1 -9
  91. classiq/qmod/symbolic_type.py +2 -1
  92. classiq/qmod/utilities.py +0 -2
  93. classiq/qmod/write_qmod.py +1 -1
  94. {classiq-0.83.0.dist-info → classiq-0.85.0.dist-info}/METADATA +4 -1
  95. {classiq-0.83.0.dist-info → classiq-0.85.0.dist-info}/RECORD +101 -90
  96. classiq/interface/model/quantum_variable_declaration.py +0 -7
  97. classiq/model_expansions/evaluators/classical_expression.py +0 -36
  98. /classiq/{model_expansions/evaluators → evaluators}/__init__.py +0 -0
  99. /classiq/{model_expansions/evaluators → evaluators}/control.py +0 -0
  100. /classiq/{model_expansions → evaluators}/expression_evaluator.py +0 -0
  101. /classiq/{model_expansions/evaluators → evaluators}/quantum_type_utils.py +0 -0
  102. /classiq/{model_expansions/evaluators → evaluators}/type_type_match.py +0 -0
  103. {classiq-0.83.0.dist-info → classiq-0.85.0.dist-info}/WHEEL +0 -0
@@ -31,7 +31,9 @@ CARRAY_ERROR_MESSAGE = (
31
31
 
32
32
 
33
33
  class PythonClassicalType:
34
- def convert(self, py_type: type) -> Optional[ConcreteClassicalType]:
34
+ def convert(
35
+ self, py_type: type, nested: bool = False
36
+ ) -> Optional[ConcreteClassicalType]:
35
37
  if py_type is int:
36
38
  return Integer().set_generative()
37
39
  elif py_type is CInt:
@@ -45,16 +47,18 @@ class PythonClassicalType:
45
47
  elif py_type is CBool:
46
48
  return Bool()
47
49
  elif get_origin(py_type) is list:
48
- element_type = self.convert(get_args(py_type)[0])
50
+ element_type = self.convert(get_args(py_type)[0], nested=True)
49
51
  if element_type is not None:
50
52
  return ClassicalArray(element_type=element_type).set_generative()
51
53
  elif get_origin(py_type) is CArray:
52
54
  array_args = version_portable_get_args(py_type)
53
55
  if len(array_args) == 1:
54
- return ClassicalArray(element_type=self.convert(array_args[0]))
56
+ return ClassicalArray(
57
+ element_type=self.convert(array_args[0], nested=True)
58
+ )
55
59
  elif len(array_args) == 2:
56
60
  return ClassicalArray(
57
- element_type=self.convert(array_args[0]),
61
+ element_type=self.convert(array_args[0], nested=True),
58
62
  length=Expression(expr=get_type_hint_expr(array_args[1])),
59
63
  )
60
64
  raise ClassiqValueError(CARRAY_ERROR_MESSAGE)
@@ -62,7 +66,10 @@ class PythonClassicalType:
62
66
  return self.register_struct(py_type)
63
67
  elif inspect.isclass(py_type) and isinstance(py_type, EnumMeta):
64
68
  self.register_enum(py_type)
65
- return Enum(name=py_type.__name__).set_generative()
69
+ enum_type = Enum(name=py_type.__name__)
70
+ if not nested:
71
+ enum_type.set_generative()
72
+ return enum_type
66
73
  elif py_type in (CArray, list):
67
74
  raise ClassiqValueError(CARRAY_ERROR_MESSAGE)
68
75
  return None
classiq/qmod/qfunc.py CHANGED
@@ -1,7 +1,6 @@
1
- import warnings
2
1
  from typing import Callable, Literal, Optional, Union, overload
3
2
 
4
- from classiq.interface.exceptions import ClassiqDeprecationWarning, ClassiqInternalError
3
+ from classiq.interface.exceptions import ClassiqInternalError
5
4
 
6
5
  from classiq.qmod.global_declarative_switch import get_global_declarative_switch
7
6
  from classiq.qmod.quantum_callable import QCallable
@@ -57,23 +56,7 @@ def qfunc(
57
56
  synthesize_separately: bool = False,
58
57
  unchecked: Optional[list[str]] = None,
59
58
  ) -> Union[Callable[[Callable], QCallable], QCallable]:
60
- if generative is True:
61
- warnings.warn(
62
- "The use of `generative=True` is no longer required. Note that the "
63
- "treatment of parameters of Qmod types will change from Python value to "
64
- "symbolic in a near release. Change Qmod types to the corresponding Python "
65
- "built-in types in order to use the parameters in Python expression "
66
- "contexts.\n"
67
- "Recommended changes:\n"
68
- "@qfunc(generative=True) -> @qfunc\n"
69
- "CInt->int\n"
70
- "CReal->float\n"
71
- "CArray->list\n\n"
72
- "For more information see https://docs.classiq.io/latest/qmod-reference/language-reference/generative-descriptions/",
73
- ClassiqDeprecationWarning,
74
- stacklevel=2,
75
- )
76
- elif generative is None:
59
+ if generative is None:
77
60
  generative = True
78
61
  if get_global_declarative_switch():
79
62
  generative = False
@@ -5,10 +5,7 @@ from typing import TYPE_CHECKING, Any, Optional, cast, get_origin
5
5
  from classiq.interface.exceptions import ClassiqError, ClassiqValueError
6
6
  from classiq.interface.generator.constant import Constant
7
7
  from classiq.interface.generator.expressions.expression import Expression
8
- from classiq.interface.generator.functions.classical_type import (
9
- ClassicalArray,
10
- ClassicalList,
11
- )
8
+ from classiq.interface.generator.functions.classical_type import ClassicalArray
12
9
 
13
10
  from classiq.qmod.cparam import CArray, CParamScalar
14
11
  from classiq.qmod.declaration_inferrer import python_type_to_qmod
@@ -118,7 +115,7 @@ class QConstant(SymbolicExpr):
118
115
  if qmod_type is None:
119
116
  raise ClassiqError("Invalid QMOD type")
120
117
 
121
- if not isinstance(qmod_type, (ClassicalList, ClassicalArray)):
118
+ if not isinstance(qmod_type, ClassicalArray):
122
119
  raise ClassiqError("Invalid subscript to non-list constant")
123
120
 
124
121
  return CParamList(
@@ -4,7 +4,6 @@ from classiq.interface.exceptions import ClassiqInternalError, ClassiqValueError
4
4
  from classiq.interface.generator.functions.classical_type import (
5
5
  Bool,
6
6
  ClassicalArray,
7
- ClassicalList,
8
7
  ClassicalTuple,
9
8
  ClassicalType,
10
9
  Integer,
@@ -42,7 +41,7 @@ class CParamList(CParam):
42
41
  def __init__(
43
42
  self,
44
43
  expr: str,
45
- list_type: Union[ClassicalList, ClassicalArray, ClassicalTuple],
44
+ list_type: Union[ClassicalArray, ClassicalTuple],
46
45
  qmodule: ModelStateContainer,
47
46
  ) -> None:
48
47
  super().__init__(expr)
@@ -149,7 +148,7 @@ def create_param(
149
148
  decl = ctype.classical_struct_decl
150
149
  ctype = Struct(name=ctype.name)
151
150
  ctype.set_classical_struct_decl(decl)
152
- if isinstance(ctype, (ClassicalList, ClassicalArray, ClassicalTuple)):
151
+ if isinstance(ctype, (ClassicalArray, ClassicalTuple)):
153
152
  return CParamList(expr_str, ctype, qmodule=qmodule)
154
153
  elif isinstance(ctype, Struct):
155
154
  return CParamStruct(expr_str, ctype, qmodule=qmodule)
@@ -164,8 +163,6 @@ def get_qmod_type(ctype: ClassicalType) -> type:
164
163
  return CReal
165
164
  elif isinstance(ctype, Bool):
166
165
  return CBool
167
- elif isinstance(ctype, ClassicalList):
168
- return CArray[get_qmod_type(ctype.element_type)] # type: ignore[misc]
169
166
  elif isinstance(ctype, ClassicalArray):
170
167
  if ctype.length is None:
171
168
  return CArray[get_qmod_type(ctype.element_type)] # type: ignore[misc]
@@ -34,19 +34,20 @@ from classiq.interface.generator.expressions.proxies.quantum.qmod_qarray_proxy i
34
34
  ILLEGAL_SLICE_MSG,
35
35
  ILLEGAL_SLICING_STEP_MSG,
36
36
  )
37
+ from classiq.interface.generator.functions.concrete_types import ConcreteQuantumType
37
38
  from classiq.interface.generator.functions.port_declaration import (
38
39
  PortDeclarationDirection,
39
40
  )
40
41
  from classiq.interface.generator.functions.type_modifier import TypeModifier
41
- from classiq.interface.generator.functions.type_name import TypeName
42
+ from classiq.interface.generator.functions.type_name import Struct, TypeName
42
43
  from classiq.interface.generator.types.qstruct_declaration import QStructDeclaration
44
+ from classiq.interface.helpers.classproperty import classproperty
43
45
  from classiq.interface.model.handle_binding import (
44
46
  FieldHandleBinding,
45
47
  HandleBinding,
46
48
  SlicedHandleBinding,
47
49
  SubscriptHandleBinding,
48
50
  )
49
- from classiq.interface.model.port_declaration import AnonPortDeclaration
50
51
  from classiq.interface.model.quantum_expressions.amplitude_loading_operation import (
51
52
  AmplitudeLoadingOperation,
52
53
  )
@@ -73,7 +74,7 @@ from classiq.qmod.quantum_callable import QCallable
73
74
  from classiq.qmod.semantics.annotation.qstruct_annotator import QStructAnnotator
74
75
  from classiq.qmod.semantics.validation.types_validation import validate_qstruct
75
76
  from classiq.qmod.symbolic_expr import Symbolic, SymbolicExpr
76
- from classiq.qmod.symbolic_type import SymbolicTypes
77
+ from classiq.qmod.symbolic_type import SYMBOLIC_TYPES, SymbolicTypes
77
78
  from classiq.qmod.utilities import (
78
79
  get_source_ref,
79
80
  unwrap_forward_ref,
@@ -103,9 +104,6 @@ def _infer_variable_name(name: Any, depth: int) -> Any:
103
104
  return name
104
105
 
105
106
 
106
- _SYMBOLIC_TYPES = tuple(get_origin(t) or t for t in get_args(SymbolicTypes))
107
-
108
-
109
107
  class QVar(Symbolic):
110
108
  CONSTRUCTOR_DEPTH: int = 1
111
109
 
@@ -136,7 +134,7 @@ class QVar(Symbolic):
136
134
  return self._base_handle
137
135
 
138
136
  @abc.abstractmethod
139
- def get_qmod_type(self) -> QuantumType:
137
+ def get_qmod_type(self) -> ConcreteQuantumType:
140
138
  raise NotImplementedError()
141
139
 
142
140
  @classmethod
@@ -164,6 +162,14 @@ class QVar(Symbolic):
164
162
  return self.get_qmod_type().type_name
165
163
 
166
164
 
165
+ class QmodExpressionCreator(Protocol):
166
+ """
167
+ A callable that creates a Qmod expression from the provided QVars.
168
+ """
169
+
170
+ def __call__(self, **kwargs: QVar) -> SymbolicExpr: ...
171
+
172
+
167
173
  _Q = TypeVar("_Q", bound=QVar)
168
174
  Output = Annotated[_Q, PortDeclarationDirection.Output]
169
175
  Input = Annotated[_Q, PortDeclarationDirection.Input]
@@ -221,7 +227,7 @@ class QScalar(QVar, SymbolicExpr):
221
227
  )
222
228
 
223
229
  def __ior__(self, other: Any) -> Self:
224
- if not isinstance(other, _SYMBOLIC_TYPES):
230
+ if not isinstance(other, SYMBOLIC_TYPES):
225
231
  raise TypeError(
226
232
  f"Invalid argument {other!r} for out-of-place arithmetic operation"
227
233
  )
@@ -232,7 +238,7 @@ class QScalar(QVar, SymbolicExpr):
232
238
  return self
233
239
 
234
240
  def __ixor__(self, other: Any) -> Self:
235
- if not isinstance(other, _SYMBOLIC_TYPES):
241
+ if not isinstance(other, SYMBOLIC_TYPES):
236
242
  raise TypeError(
237
243
  f"Invalid argument {other!r} for in-place arithmetic operation"
238
244
  )
@@ -243,7 +249,7 @@ class QScalar(QVar, SymbolicExpr):
243
249
  return self
244
250
 
245
251
  def __iadd__(self, other: Any) -> Self:
246
- if not isinstance(other, _SYMBOLIC_TYPES):
252
+ if not isinstance(other, SYMBOLIC_TYPES):
247
253
  raise TypeError(
248
254
  f"Invalid argument {other!r} for in-place arithmetic operation"
249
255
  )
@@ -254,7 +260,7 @@ class QScalar(QVar, SymbolicExpr):
254
260
  return self
255
261
 
256
262
  def __imul__(self, other: Any) -> Self:
257
- if not isinstance(other, _SYMBOLIC_TYPES):
263
+ if not isinstance(other, SYMBOLIC_TYPES):
258
264
  raise TypeError(
259
265
  f"Invalid argument {other!r} for out of ampltiude encoding operation"
260
266
  )
@@ -273,7 +279,7 @@ class QBit(QScalar):
273
279
  ) -> "QBit":
274
280
  return QBit(origin, _expr_str=expr_str)
275
281
 
276
- def get_qmod_type(self) -> QuantumType:
282
+ def get_qmod_type(self) -> ConcreteQuantumType:
277
283
  return QuantumBit()
278
284
 
279
285
 
@@ -329,7 +335,7 @@ class QNum(Generic[_P], QScalar):
329
335
  ) -> "QNum":
330
336
  return QNum(origin, *_get_qnum_attributes(type_hint), _expr_str=expr_str)
331
337
 
332
- def get_qmod_type(self) -> QuantumType:
338
+ def get_qmod_type(self) -> ConcreteQuantumType:
333
339
  return QuantumNumeric(
334
340
  size=self._size,
335
341
  is_signed=self._is_signed,
@@ -498,8 +504,15 @@ class QStruct(QVar):
498
504
  setattr(self, field_name, var)
499
505
  super().__init__(name, expr_str=_expr_str)
500
506
 
501
- def get_qmod_type(self) -> QuantumType:
502
- return TypeName(name=self._struct_name)
507
+ def get_qmod_type(self) -> ConcreteQuantumType:
508
+ classical_type = Struct(name=self._struct_name)
509
+ classical_type.set_fields(
510
+ {
511
+ field_name: field_var.get_qmod_type()
512
+ for field_name, field_var in self._fields.items()
513
+ }
514
+ )
515
+ return classical_type
503
516
 
504
517
  @classmethod
505
518
  def to_qvar(
@@ -529,9 +542,23 @@ class QStruct(QVar):
529
542
  _expr_str=expr_str,
530
543
  )
531
544
 
545
+ @classproperty
546
+ def num_qubits(cls) -> int: # noqa: N805
547
+ """
548
+ The total number of qubits in this quantum struct.
549
+ Raises an error if the struct doesn't have a fixed size.
550
+ """
551
+ qvar = cls.to_qvar(HandleBinding(name="dummy"), type_hint=cls, expr_str=None)
552
+ quantum_type = qvar.get_qmod_type()
553
+ if not quantum_type.has_size_in_bits:
554
+ raise ClassiqValueError(
555
+ f"Could not infer the size of struct {qvar._struct_name!r}"
556
+ )
557
+ return quantum_type.size_in_bits
558
+
532
559
 
533
- def create_qvar_for_port_decl(port: AnonPortDeclaration, name: str) -> QVar:
534
- return _create_qvar_for_qtype(port.quantum_type, HandleBinding(name=name))
560
+ def create_qvar_from_quantum_type(quantum_type: ConcreteQuantumType, name: str) -> QVar:
561
+ return _create_qvar_for_qtype(quantum_type, HandleBinding(name=name))
535
562
 
536
563
 
537
564
  def _create_qvar_for_qtype(
@@ -689,17 +716,27 @@ def _get_quantum_bit_vector(type_hint: type[QArray]) -> QuantumBitvector:
689
716
  return QuantumBitvector(element_type=element_type, length=length_expr)
690
717
 
691
718
 
692
- def _get_quantum_struct(type_hint: type[QStruct]) -> TypeName:
693
- _register_qstruct(type_hint, qmodule=QMODULE)
694
- return TypeName(name=type_hint.__name__)
719
+ def _get_quantum_struct(type_hint: type[QStruct]) -> Struct:
720
+ decl = _register_qstruct(type_hint, qmodule=QMODULE)
721
+ classical_type = Struct(name=type_hint.__name__)
722
+ if decl is not None:
723
+ classical_type.set_fields(
724
+ {
725
+ field_name: field_type.model_copy(deep=True)
726
+ for field_name, field_type in decl.fields.items()
727
+ }
728
+ )
729
+ return classical_type
695
730
 
696
731
 
697
732
  def _register_qstruct(
698
733
  type_hint: type[QStruct], *, qmodule: ModelStateContainer
699
- ) -> None:
734
+ ) -> Optional[QStructDeclaration]:
700
735
  struct_name = type_hint.__name__
701
- if type_hint is QStruct or struct_name in qmodule.qstruct_decls:
702
- return
736
+ if type_hint is QStruct:
737
+ return None
738
+ if struct_name in qmodule.qstruct_decls:
739
+ return qmodule.qstruct_decls[struct_name]
703
740
 
704
741
  # temp assignment for recursive qstruct definitions
705
742
  qmodule.qstruct_decls[struct_name] = QStructDeclaration(name=struct_name)
@@ -714,6 +751,7 @@ def _register_qstruct(
714
751
  qmodule.qstruct_decls[struct_name] = struct_decl
715
752
  QStructAnnotator().visit(struct_decl)
716
753
  validate_qstruct(struct_decl)
754
+ return struct_decl
717
755
 
718
756
 
719
757
  def _validate_fields(type_hint: type[QStruct]) -> None:
@@ -68,7 +68,7 @@ from classiq.qmod.qmod_parameter import (
68
68
  )
69
69
  from classiq.qmod.qmod_variable import (
70
70
  QVar,
71
- create_qvar_for_port_decl,
71
+ create_qvar_from_quantum_type,
72
72
  )
73
73
  from classiq.qmod.quantum_callable import QCallable, QExpandableInterface
74
74
  from classiq.qmod.symbolic_expr import SymbolicExpr
@@ -135,7 +135,7 @@ class QExpandable(QCallable, QExpandableInterface, ABC):
135
135
  ) -> None:
136
136
  self.append_statement_to_body(
137
137
  VariableDeclarationStatement(
138
- name=name, quantum_type=qtype, source_ref=source_ref
138
+ name=name, qmod_type=qtype, source_ref=source_ref
139
139
  )
140
140
  )
141
141
 
@@ -163,7 +163,9 @@ class QExpandable(QCallable, QExpandableInterface, ABC):
163
163
  create_param(actual_name, arg.classical_type, self._qmodule)
164
164
  )
165
165
  elif isinstance(arg, AnonPortDeclaration):
166
- result.append(create_qvar_for_port_decl(arg, actual_name))
166
+ result.append(
167
+ create_qvar_from_quantum_type(arg.quantum_type, actual_name)
168
+ )
167
169
  else:
168
170
  assert isinstance(arg, AnonQuantumOperandDeclaration)
169
171
  result.append(QTerminalCallable(arg, idx))
@@ -1,12 +1,13 @@
1
1
  import ast
2
2
  import functools
3
+ import warnings
3
4
  from abc import abstractmethod
4
5
  from dataclasses import is_dataclass
5
6
  from enum import EnumMeta
6
7
  from inspect import isclass
7
8
  from typing import Any, Callable, Optional, get_origin
8
9
 
9
- from classiq.interface.exceptions import ClassiqError
10
+ from classiq.interface.exceptions import ClassiqDeprecationWarning, ClassiqError
10
11
  from classiq.interface.executor.execution_preferences import ExecutionPreferences
11
12
  from classiq.interface.generator.functions.port_declaration import (
12
13
  PortDeclarationDirection,
@@ -28,7 +29,7 @@ from classiq.qmod.declaration_inferrer import infer_func_decl, is_qvar
28
29
  from classiq.qmod.generative import set_frontend_interpreter
29
30
  from classiq.qmod.global_declarative_switch import get_global_declarative_switch
30
31
  from classiq.qmod.qmod_constant import QConstant
31
- from classiq.qmod.qmod_parameter import CArray
32
+ from classiq.qmod.qmod_parameter import CArray, CParamList
32
33
  from classiq.qmod.quantum_callable import QCallable, QCallableList
33
34
  from classiq.qmod.quantum_expandable import QExpandable, QTerminalCallable
34
35
  from classiq.qmod.semantics.annotation.qstruct_annotator import QStructAnnotator
@@ -101,7 +102,12 @@ class QFunc(BaseQFunc):
101
102
  ) -> None:
102
103
  _validate_no_gen_params(py_callable.__annotations__)
103
104
  super().__init__(py_callable, compilation_metadata)
104
- self.compilation_metadata: Optional[CompilationMetadata] = None
105
+ if compilation_metadata is not None and compilation_metadata.unchecked:
106
+ self.compilation_metadata: Optional[CompilationMetadata] = (
107
+ CompilationMetadata(unchecked=compilation_metadata.unchecked)
108
+ )
109
+ else:
110
+ self.compilation_metadata = None
105
111
 
106
112
  @property
107
113
  def func_decl(self) -> NamedParamsQuantumFunctionDeclaration:
@@ -213,6 +219,7 @@ class QFunc(BaseQFunc):
213
219
 
214
220
 
215
221
  class ExternalQFunc(QTerminalCallable):
222
+ FRAME_DEPTH = 2 # FIXME: Remove (CLS-2912)
216
223
  _decl: NamedParamsQuantumFunctionDeclaration
217
224
 
218
225
  def __init__(self, py_callable: Callable) -> None:
@@ -237,6 +244,44 @@ class ExternalQFunc(QTerminalCallable):
237
244
  def pure_decl(self) -> NamedParamsQuantumFunctionDeclaration:
238
245
  return self.func_decl
239
246
 
247
+ def __call__(self, *args: Any, **kwargs: Any) -> None:
248
+ if self._py_callable.__name__ == "parametric_suzuki_trotter":
249
+ warnings.warn(
250
+ (
251
+ "Function 'parametric_suzuki_trotter' is deprecated and will no "
252
+ "longer be supported starting on 21/7/2025 at the earliest. "
253
+ "Instead, use 'multi_suzuki_trotter'."
254
+ ),
255
+ ClassiqDeprecationWarning,
256
+ stacklevel=2,
257
+ )
258
+ if self._py_callable.__name__ == "sparse_suzuki_trotter":
259
+ warnings.warn(
260
+ (
261
+ "Function 'sparse_suzuki_trotter' is deprecated and will no "
262
+ "longer be supported starting on 21/7/2025 at the earliest. "
263
+ "Instead, use 'suzuki_trotter'."
264
+ ),
265
+ ClassiqDeprecationWarning,
266
+ stacklevel=2,
267
+ )
268
+ if (
269
+ self._py_callable.__name__ == "suzuki_trotter"
270
+ and len(args) > 0
271
+ and isinstance(args[0], (list, CParamList))
272
+ ):
273
+ warnings.warn(
274
+ (
275
+ "Parameter type CArray[PauliTerm] to function 'suzuki_trotter' is "
276
+ "deprecated and will no longer be supported starting on 21/7/2025 "
277
+ "at the earliest. Instead, send a 'SparsePauliOp' (see "
278
+ "https://docs.classiq.io/latest/qmod-reference/language-reference/classical-types/#hamiltonians)."
279
+ ),
280
+ ClassiqDeprecationWarning,
281
+ stacklevel=2,
282
+ )
283
+ super().__call__(*args, **kwargs)
284
+
240
285
 
241
286
  class GenerativeQFunc(BaseQFunc):
242
287
  FRAME_DEPTH = 3
@@ -261,7 +306,7 @@ class GenerativeQFunc(BaseQFunc):
261
306
 
262
307
  def __call__(self, *args: Any, **kwargs: Any) -> None:
263
308
  if get_global_declarative_switch():
264
- return QFunc(self._py_callable)(*args, **kwargs)
309
+ return QFunc(self._py_callable, self.compilation_metadata)(*args, **kwargs)
265
310
  if self.func_decl.name not in self._qmodule.generative_functions:
266
311
  self._qmodule.generative_functions[self.func_decl.name] = self
267
312
  if self._func_decl is None:
@@ -45,7 +45,7 @@ class QStructAnnotator(ModelVisitor):
45
45
  return
46
46
  self._visited.add(type_name)
47
47
  new_fields = {
48
- field_name: field_type.model_copy()
48
+ field_name: field_type.model_copy(deep=True)
49
49
  for field_name, field_type in decl.variables.items()
50
50
  }
51
51
  self.visit(new_fields)
@@ -1,8 +1,5 @@
1
1
  from classiq.interface.exceptions import ClassiqExpansionError, ClassiqValueError
2
- from classiq.interface.generator.functions.classical_type import (
3
- ClassicalArray,
4
- ClassicalList,
5
- )
2
+ from classiq.interface.generator.functions.classical_type import ClassicalArray
6
3
  from classiq.interface.generator.functions.concrete_types import ConcreteClassicalType
7
4
  from classiq.interface.generator.functions.port_declaration import (
8
5
  PortDeclarationDirection,
@@ -31,11 +28,6 @@ def _validate_main_param(param: PositionalArg) -> None:
31
28
  def _validate_main_classical_param_type(
32
29
  param: ConcreteClassicalType, param_name: str
33
30
  ) -> None:
34
- if isinstance(param, ClassicalList):
35
- raise ClassiqExpansionError(
36
- f"Classical array parameter {param_name!r} of function 'main' must "
37
- f"specify array length",
38
- )
39
31
  if isinstance(param, ClassicalArray):
40
32
  if param.length is None:
41
33
  raise ClassiqExpansionError(
@@ -1,5 +1,6 @@
1
- from typing import Union
1
+ from typing import Union, get_args, get_origin
2
2
 
3
3
  from classiq.qmod.symbolic_expr import SymbolicExpr
4
4
 
5
5
  SymbolicTypes = Union[SymbolicExpr, int, float, bool, tuple["SymbolicTypes", ...]]
6
+ SYMBOLIC_TYPES = tuple(get_origin(t) or t for t in get_args(SymbolicTypes))
classiq/qmod/utilities.py CHANGED
@@ -31,8 +31,6 @@ from classiq.interface.source_reference import SourceReference
31
31
  if TYPE_CHECKING:
32
32
  from classiq.qmod.qmod_variable import QVar
33
33
 
34
- DEFAULT_DECIMAL_PRECISION = 4
35
-
36
34
 
37
35
  def mangle_keyword(name: str) -> str:
38
36
  if keyword.iskeyword(name):
@@ -2,12 +2,12 @@ import json
2
2
  from pathlib import Path
3
3
  from typing import Optional, Union
4
4
 
5
+ from classiq.interface.constants import DEFAULT_DECIMAL_PRECISION
5
6
  from classiq.interface.model.model import Model, SerializedModel
6
7
 
7
8
  from classiq.qmod.global_declarative_switch import set_global_declarative_switch
8
9
  from classiq.qmod.native.pretty_printer import DSLPrettyPrinter
9
10
  from classiq.qmod.quantum_function import GenerativeQFunc, QFunc
10
- from classiq.qmod.utilities import DEFAULT_DECIMAL_PRECISION
11
11
 
12
12
  _QMOD_SUFFIX = "qmod"
13
13
  _SYNTHESIS_OPTIONS_SUFFIX = "synthesis_options.json"
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.3
2
2
  Name: classiq
3
- Version: 0.83.0
3
+ Version: 0.85.0
4
4
  Summary: Classiq's Python SDK for quantum computing
5
5
  License: Proprietary
6
6
  Keywords: quantum computing,quantum circuits,quantum algorithms,QAD,QDL
@@ -27,6 +27,7 @@ Classifier: Topic :: Software Development :: Compilers
27
27
  Classifier: Topic :: Software Development :: Libraries :: Python Modules
28
28
  Classifier: Typing :: Typed
29
29
  Provides-Extra: analyzer-sdk
30
+ Provides-Extra: chemistry
30
31
  Provides-Extra: qml
31
32
  Requires-Dist: ConfigArgParse (>=1.5.3,<2.0.0)
32
33
  Requires-Dist: Pyomo (>=6.5,<6.6)
@@ -41,6 +42,8 @@ Requires-Dist: notebook ; extra == "analyzer-sdk"
41
42
  Requires-Dist: numexpr (>=2.7.3,<3.0.0)
42
43
  Requires-Dist: numpy (>=1.20.1,<2.0.0) ; python_version < "3.12"
43
44
  Requires-Dist: numpy (>=1.26.0,<2.0.0) ; python_version >= "3.12"
45
+ Requires-Dist: openfermion ; extra == "chemistry"
46
+ Requires-Dist: openfermionpyscf ; extra == "chemistry"
44
47
  Requires-Dist: packaging (>=23.2,<24.0)
45
48
  Requires-Dist: pandas (>=1.4.0,<3.0.0)
46
49
  Requires-Dist: plotly (>=5.7.0,<6.0.0)