classiq 0.93.0__py3-none-any.whl → 0.94.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.

Potentially problematic release.


This version of classiq might be problematic. Click here for more details.

Files changed (261) hide show
  1. classiq/__init__.py +6 -19
  2. classiq/_analyzer_extras/_ipywidgets_async_extension.py +7 -7
  3. classiq/_analyzer_extras/interactive_hardware.py +19 -12
  4. classiq/_internals/api_wrapper.py +38 -52
  5. classiq/_internals/async_utils.py +4 -7
  6. classiq/_internals/authentication/auth0.py +3 -3
  7. classiq/_internals/authentication/device.py +4 -4
  8. classiq/_internals/authentication/password_manager.py +13 -13
  9. classiq/_internals/authentication/token_manager.py +4 -5
  10. classiq/_internals/client.py +17 -44
  11. classiq/_internals/config.py +1 -2
  12. classiq/_internals/help.py +1 -2
  13. classiq/_internals/host_checker.py +3 -3
  14. classiq/_internals/jobs.py +14 -14
  15. classiq/_internals/type_validation.py +3 -3
  16. classiq/analyzer/analyzer.py +18 -18
  17. classiq/analyzer/rb.py +17 -8
  18. classiq/applications/chemistry/__init__.py +0 -30
  19. classiq/applications/chemistry/op_utils.py +4 -4
  20. classiq/applications/chemistry/problems.py +3 -3
  21. classiq/applications/chemistry/ucc.py +1 -2
  22. classiq/applications/chemistry/z2_symmetries.py +4 -4
  23. classiq/applications/combinatorial_helpers/allowed_constraints.py +1 -3
  24. classiq/applications/combinatorial_helpers/arithmetic/arithmetic_expression.py +2 -1
  25. classiq/applications/combinatorial_helpers/combinatorial_problem_utils.py +2 -2
  26. classiq/applications/combinatorial_helpers/encoding_mapping.py +2 -3
  27. classiq/applications/combinatorial_helpers/encoding_utils.py +2 -2
  28. classiq/applications/combinatorial_helpers/optimization_model.py +3 -4
  29. classiq/applications/combinatorial_helpers/pauli_helpers/pauli_sparsing.py +2 -2
  30. classiq/applications/combinatorial_helpers/pyomo_utils.py +8 -8
  31. classiq/applications/combinatorial_helpers/sympy_utils.py +1 -3
  32. classiq/applications/combinatorial_helpers/transformations/encoding.py +3 -3
  33. classiq/applications/combinatorial_helpers/transformations/fixed_variables.py +1 -2
  34. classiq/applications/combinatorial_optimization/combinatorial_optimization_config.py +2 -3
  35. classiq/applications/combinatorial_optimization/combinatorial_optimization_model_constructor.py +4 -6
  36. classiq/applications/combinatorial_optimization/combinatorial_problem.py +15 -10
  37. classiq/applications/hamiltonian/pauli_decomposition.py +6 -4
  38. classiq/applications/iqae/iqae.py +8 -8
  39. classiq/applications/qnn/datasets/dataset_base_classes.py +6 -6
  40. classiq/applications/qnn/datasets/dataset_parity.py +6 -6
  41. classiq/applications/qnn/qlayer.py +8 -7
  42. classiq/applications/qnn/torch_utils.py +3 -4
  43. classiq/applications/qnn/types.py +2 -1
  44. classiq/applications/qsp/qsp.py +5 -4
  45. classiq/applications/qsvm/qsvm_data_generation.py +1 -2
  46. classiq/evaluators/classical_expression.py +0 -4
  47. classiq/evaluators/parameter_types.py +7 -8
  48. classiq/evaluators/qmod_annotated_expression.py +24 -26
  49. classiq/evaluators/qmod_expression_visitors/qmod_expression_evaluator.py +14 -14
  50. classiq/evaluators/qmod_expression_visitors/qmod_expression_simplifier.py +2 -1
  51. classiq/evaluators/qmod_expression_visitors/sympy_wrappers.py +8 -8
  52. classiq/evaluators/qmod_node_evaluators/classical_function_evaluation.py +4 -4
  53. classiq/evaluators/qmod_node_evaluators/list_evaluation.py +2 -2
  54. classiq/evaluators/qmod_node_evaluators/numeric_attrs_utils.py +3 -3
  55. classiq/evaluators/qmod_node_evaluators/subscript_evaluation.py +9 -9
  56. classiq/evaluators/qmod_node_evaluators/utils.py +6 -6
  57. classiq/evaluators/qmod_type_inference/classical_type_inference.py +9 -10
  58. classiq/evaluators/qmod_type_inference/quantum_type_inference.py +5 -5
  59. classiq/execution/execution_session.py +18 -19
  60. classiq/execution/jobs.py +26 -26
  61. classiq/execution/qnn.py +1 -2
  62. classiq/execution/user_budgets.py +52 -7
  63. classiq/executor.py +1 -3
  64. classiq/interface/_version.py +1 -1
  65. classiq/interface/analyzer/analysis_params.py +4 -4
  66. classiq/interface/analyzer/cytoscape_graph.py +3 -3
  67. classiq/interface/analyzer/result.py +4 -4
  68. classiq/interface/applications/qsvm.py +5 -8
  69. classiq/interface/ast_node.py +3 -3
  70. classiq/interface/backend/backend_preferences.py +16 -16
  71. classiq/interface/backend/ionq/ionq_quantum_program.py +5 -5
  72. classiq/interface/chemistry/ansatz_library.py +3 -5
  73. classiq/interface/chemistry/operator.py +3 -3
  74. classiq/interface/combinatorial_optimization/examples/knapsack.py +2 -4
  75. classiq/interface/combinatorial_optimization/examples/tsp_digraph.py +1 -2
  76. classiq/interface/compression_utils.py +2 -3
  77. classiq/interface/debug_info/debug_info.py +7 -7
  78. classiq/interface/exceptions.py +2 -3
  79. classiq/interface/execution/iqcc.py +1 -3
  80. classiq/interface/execution/primitives.py +6 -6
  81. classiq/interface/executor/estimate_cost.py +1 -1
  82. classiq/interface/executor/execution_preferences.py +3 -5
  83. classiq/interface/executor/execution_request.py +10 -10
  84. classiq/interface/executor/execution_result.py +1 -2
  85. classiq/interface/executor/quantum_code.py +8 -8
  86. classiq/interface/executor/result.py +28 -18
  87. classiq/interface/executor/user_budget.py +2 -3
  88. classiq/interface/executor/vqe_result.py +5 -6
  89. classiq/interface/generator/ansatz_library.py +6 -8
  90. classiq/interface/generator/application_apis/__init__.py +0 -2
  91. classiq/interface/generator/arith/arithmetic.py +2 -2
  92. classiq/interface/generator/arith/arithmetic_arg_type_validator.py +2 -3
  93. classiq/interface/generator/arith/arithmetic_expression_abc.py +4 -5
  94. classiq/interface/generator/arith/arithmetic_expression_parser.py +11 -4
  95. classiq/interface/generator/arith/arithmetic_expression_validator.py +12 -15
  96. classiq/interface/generator/arith/arithmetic_operations.py +4 -6
  97. classiq/interface/generator/arith/arithmetic_param_getters.py +70 -107
  98. classiq/interface/generator/arith/arithmetic_result_builder.py +4 -4
  99. classiq/interface/generator/arith/ast_node_rewrite.py +8 -4
  100. classiq/interface/generator/arith/binary_ops.py +7 -36
  101. classiq/interface/generator/arith/logical_ops.py +2 -3
  102. classiq/interface/generator/arith/number_utils.py +2 -2
  103. classiq/interface/generator/arith/register_user_input.py +2 -2
  104. classiq/interface/generator/arith/unary_ops.py +2 -2
  105. classiq/interface/generator/circuit_code/circuit_code.py +8 -10
  106. classiq/interface/generator/circuit_code/types_and_constants.py +1 -1
  107. classiq/interface/generator/complex_type.py +2 -2
  108. classiq/interface/generator/copy.py +1 -3
  109. classiq/interface/generator/expressions/atomic_expression_functions.py +0 -5
  110. classiq/interface/generator/expressions/evaluated_expression.py +2 -3
  111. classiq/interface/generator/expressions/expression.py +2 -2
  112. classiq/interface/generator/expressions/proxies/classical/classical_array_proxy.py +4 -7
  113. classiq/interface/generator/function_param_list.py +0 -20
  114. classiq/interface/generator/function_params.py +5 -6
  115. classiq/interface/generator/functions/classical_function_declaration.py +2 -2
  116. classiq/interface/generator/functions/classical_type.py +3 -3
  117. classiq/interface/generator/functions/type_modifier.py +0 -14
  118. classiq/interface/generator/functions/type_name.py +2 -2
  119. classiq/interface/generator/generated_circuit_data.py +12 -13
  120. classiq/interface/generator/hamiltonian_evolution/exponentiation.py +2 -4
  121. classiq/interface/generator/hardware/hardware_data.py +8 -8
  122. classiq/interface/generator/hardware_efficient_ansatz.py +8 -8
  123. classiq/interface/generator/mcu.py +3 -3
  124. classiq/interface/generator/mcx.py +3 -3
  125. classiq/interface/generator/model/constraints.py +34 -5
  126. classiq/interface/generator/model/preferences/preferences.py +15 -21
  127. classiq/interface/generator/model/quantum_register.py +7 -10
  128. classiq/interface/generator/noise_properties.py +3 -7
  129. classiq/interface/generator/parameters.py +1 -1
  130. classiq/interface/generator/partitioned_register.py +1 -2
  131. classiq/interface/generator/preferences/qasm_to_qmod_params.py +11 -0
  132. classiq/interface/generator/qsvm.py +2 -2
  133. classiq/interface/generator/quantum_function_call.py +8 -11
  134. classiq/interface/generator/quantum_program.py +12 -15
  135. classiq/interface/generator/range_types.py +3 -3
  136. classiq/interface/generator/slice_parsing_utils.py +4 -5
  137. classiq/interface/generator/standard_gates/standard_gates.py +2 -4
  138. classiq/interface/generator/state_preparation/state_preparation.py +6 -8
  139. classiq/interface/generator/synthesis_execution_parameter.py +1 -3
  140. classiq/interface/generator/synthesis_metadata/synthesis_execution_data.py +2 -3
  141. classiq/interface/generator/transpiler_basis_gates.py +2 -4
  142. classiq/interface/generator/types/builtin_enum_declarations.py +0 -136
  143. classiq/interface/generator/types/compilation_metadata.py +12 -1
  144. classiq/interface/generator/types/enum_declaration.py +2 -1
  145. classiq/interface/generator/validations/flow_graph.py +3 -3
  146. classiq/interface/generator/visitor.py +10 -12
  147. classiq/interface/hardware.py +2 -2
  148. classiq/interface/helpers/classproperty.py +2 -2
  149. classiq/interface/helpers/custom_encoders.py +2 -1
  150. classiq/interface/helpers/custom_pydantic_types.py +1 -1
  151. classiq/interface/helpers/text_utils.py +1 -4
  152. classiq/interface/ide/visual_model.py +5 -5
  153. classiq/interface/jobs.py +3 -3
  154. classiq/interface/model/allocate.py +4 -4
  155. classiq/interface/model/block.py +2 -2
  156. classiq/interface/model/bounds.py +3 -3
  157. classiq/interface/model/control.py +1 -1
  158. classiq/interface/model/inplace_binary_operation.py +2 -2
  159. classiq/interface/model/model.py +4 -4
  160. classiq/interface/model/parameter.py +1 -3
  161. classiq/interface/model/port_declaration.py +1 -1
  162. classiq/interface/model/quantum_expressions/quantum_expression.py +1 -2
  163. classiq/interface/model/quantum_function_call.py +3 -6
  164. classiq/interface/model/quantum_function_declaration.py +1 -0
  165. classiq/interface/model/quantum_lambda_function.py +4 -4
  166. classiq/interface/model/quantum_statement.py +4 -4
  167. classiq/interface/model/quantum_type.py +14 -14
  168. classiq/interface/model/validation_handle.py +2 -3
  169. classiq/interface/model/variable_declaration_statement.py +2 -2
  170. classiq/interface/pretty_print/expression_to_qmod.py +3 -4
  171. classiq/interface/server/routes.py +0 -4
  172. classiq/interface/source_reference.py +3 -4
  173. classiq/model_expansions/arithmetic.py +6 -7
  174. classiq/model_expansions/arithmetic_compute_result_attrs.py +4 -5
  175. classiq/model_expansions/capturing/captured_vars.py +3 -3
  176. classiq/model_expansions/capturing/mangling_utils.py +1 -2
  177. classiq/model_expansions/closure.py +12 -11
  178. classiq/model_expansions/function_builder.py +14 -6
  179. classiq/model_expansions/generative_functions.py +1 -4
  180. classiq/model_expansions/interpreters/base_interpreter.py +2 -6
  181. classiq/model_expansions/interpreters/generative_interpreter.py +5 -3
  182. classiq/model_expansions/quantum_operations/allocate.py +4 -4
  183. classiq/model_expansions/quantum_operations/assignment_result_processor.py +2 -4
  184. classiq/model_expansions/quantum_operations/call_emitter.py +31 -37
  185. classiq/model_expansions/quantum_operations/declarative_call_emitter.py +2 -2
  186. classiq/model_expansions/quantum_operations/emitter.py +3 -5
  187. classiq/model_expansions/quantum_operations/expression_evaluator.py +3 -3
  188. classiq/model_expansions/quantum_operations/skip_control_verifier.py +1 -2
  189. classiq/model_expansions/quantum_operations/variable_decleration.py +2 -2
  190. classiq/model_expansions/scope.py +7 -7
  191. classiq/model_expansions/scope_initialization.py +4 -0
  192. classiq/model_expansions/visitors/symbolic_param_inference.py +3 -3
  193. classiq/model_expansions/visitors/uncomputation_signature_inference.py +317 -0
  194. classiq/model_expansions/visitors/variable_references.py +15 -14
  195. classiq/open_library/functions/__init__.py +6 -0
  196. classiq/open_library/functions/discrete_sine_cosine_transform.py +5 -5
  197. classiq/open_library/functions/grover.py +8 -10
  198. classiq/open_library/functions/modular_exponentiation.py +96 -8
  199. classiq/qmod/__init__.py +5 -2
  200. classiq/qmod/builtins/classical_execution_primitives.py +4 -11
  201. classiq/qmod/builtins/classical_functions.py +1 -42
  202. classiq/qmod/builtins/enums.py +0 -136
  203. classiq/qmod/builtins/functions/__init__.py +0 -13
  204. classiq/qmod/builtins/functions/allocation.py +4 -4
  205. classiq/qmod/builtins/functions/arithmetic.py +22 -27
  206. classiq/qmod/builtins/functions/standard_gates.py +27 -27
  207. classiq/qmod/builtins/operations.py +35 -58
  208. classiq/qmod/builtins/structs.py +2 -58
  209. classiq/qmod/cfunc.py +3 -2
  210. classiq/qmod/classical_function.py +2 -1
  211. classiq/qmod/cparam.py +2 -8
  212. classiq/qmod/create_model_function.py +7 -7
  213. classiq/qmod/declaration_inferrer.py +33 -30
  214. classiq/qmod/model_state_container.py +2 -2
  215. classiq/qmod/native/pretty_printer.py +25 -14
  216. classiq/qmod/pretty_print/expression_to_python.py +5 -3
  217. classiq/qmod/pretty_print/pretty_printer.py +39 -17
  218. classiq/qmod/python_classical_type.py +40 -13
  219. classiq/qmod/qfunc.py +139 -16
  220. classiq/qmod/qmod_constant.py +2 -2
  221. classiq/qmod/qmod_parameter.py +5 -2
  222. classiq/qmod/qmod_variable.py +47 -43
  223. classiq/qmod/quantum_callable.py +18 -13
  224. classiq/qmod/quantum_expandable.py +31 -26
  225. classiq/qmod/quantum_function.py +51 -32
  226. classiq/qmod/semantics/annotation/call_annotation.py +2 -2
  227. classiq/qmod/semantics/error_manager.py +5 -6
  228. classiq/qmod/semantics/lambdas.py +1 -2
  229. classiq/qmod/semantics/validation/types_validation.py +1 -2
  230. classiq/qmod/symbolic.py +2 -4
  231. classiq/qmod/utilities.py +13 -10
  232. classiq/qmod/write_qmod.py +3 -4
  233. classiq/quantum_program.py +1 -3
  234. classiq/synthesis.py +11 -7
  235. {classiq-0.93.0.dist-info → classiq-0.94.0.dist-info}/METADATA +2 -3
  236. {classiq-0.93.0.dist-info → classiq-0.94.0.dist-info}/RECORD +238 -260
  237. classiq/applications/chemistry/ansatz_parameters.py +0 -29
  238. classiq/applications/chemistry/chemistry_execution_parameters.py +0 -16
  239. classiq/applications/chemistry/chemistry_model_constructor.py +0 -532
  240. classiq/applications/chemistry/ground_state_problem.py +0 -42
  241. classiq/evaluators/qmod_expression_visitors/qmod_expression_bwc.py +0 -129
  242. classiq/interface/chemistry/elements.py +0 -120
  243. classiq/interface/chemistry/fermionic_operator.py +0 -208
  244. classiq/interface/chemistry/ground_state_problem.py +0 -132
  245. classiq/interface/chemistry/ground_state_result.py +0 -8
  246. classiq/interface/chemistry/molecule.py +0 -71
  247. classiq/interface/generator/application_apis/chemistry_declarations.py +0 -69
  248. classiq/interface/generator/application_apis/entangler_declarations.py +0 -29
  249. classiq/interface/generator/chemistry_function_params.py +0 -50
  250. classiq/interface/generator/entangler_params.py +0 -72
  251. classiq/interface/generator/entanglers.py +0 -14
  252. classiq/interface/generator/hartree_fock.py +0 -26
  253. classiq/interface/generator/hva.py +0 -22
  254. classiq/interface/generator/linear_pauli_rotations.py +0 -92
  255. classiq/interface/generator/qft.py +0 -37
  256. classiq/interface/generator/ucc.py +0 -74
  257. classiq/interface/helpers/backward_compatibility.py +0 -9
  258. classiq/model_expansions/transformers/type_modifier_inference.py +0 -392
  259. classiq/qmod/builtins/functions/chemistry.py +0 -123
  260. {classiq-0.93.0.dist-info → classiq-0.94.0.dist-info}/WHEEL +0 -0
  261. {classiq-0.93.0.dist-info → classiq-0.94.0.dist-info}/licenses/LICENSE.txt +0 -0
@@ -1,12 +1,10 @@
1
1
  import dataclasses
2
- import sys
3
- from collections.abc import Sequence
2
+ from collections.abc import Callable, Sequence
4
3
  from enum import EnumMeta
5
4
  from typing import (
5
+ Annotated,
6
6
  Any,
7
- Callable,
8
7
  Literal,
9
- Optional,
10
8
  get_args,
11
9
  get_origin,
12
10
  overload,
@@ -39,21 +37,22 @@ from classiq.qmod.builtins.structs import BUILTIN_STRUCT_DECLARATIONS
39
37
  from classiq.qmod.model_state_container import ModelStateContainer
40
38
  from classiq.qmod.python_classical_type import PythonClassicalType
41
39
  from classiq.qmod.qmod_variable import QVar, get_port_from_type_hint
42
- from classiq.qmod.quantum_callable import QCallableList
40
+ from classiq.qmod.quantum_callable import QCallable, QCallableList, QPerm, QPermList
43
41
  from classiq.qmod.semantics.annotation.qstruct_annotator import QStructAnnotator
44
42
  from classiq.qmod.semantics.validation.type_hints import validate_annotation
45
43
  from classiq.qmod.semantics.validation.types_validation import (
46
44
  check_duplicate_types,
47
45
  validate_cstruct,
48
46
  )
49
- from classiq.qmod.utilities import unmangle_keyword, version_portable_get_args
50
-
51
- if sys.version_info[0:2] >= (3, 9):
52
- from typing import Annotated
47
+ from classiq.qmod.utilities import (
48
+ type_to_str,
49
+ unmangle_keyword,
50
+ version_portable_get_args,
51
+ )
53
52
 
54
53
 
55
54
  class _PythonClassicalType(PythonClassicalType):
56
- def __init__(self, qmodule: Optional[ModelStateContainer]):
55
+ def __init__(self, qmodule: ModelStateContainer | None):
57
56
  super().__init__()
58
57
  self.qmodule = qmodule
59
58
 
@@ -97,12 +96,12 @@ class _PythonClassicalType(PythonClassicalType):
97
96
 
98
97
 
99
98
  def python_type_to_qmod(
100
- py_type: type, *, qmodule: Optional[ModelStateContainer]
101
- ) -> Optional[ConcreteClassicalType]:
99
+ py_type: type, *, qmodule: ModelStateContainer | None
100
+ ) -> ConcreteClassicalType | None:
102
101
  return _PythonClassicalType(qmodule).convert(py_type)
103
102
 
104
103
 
105
- def _extract_port_decl(name: Optional[str], py_type: Any) -> AnonPortDeclaration:
104
+ def _extract_port_decl(name: str | None, py_type: Any) -> AnonPortDeclaration:
106
105
  quantum_type, direction, modifier = get_port_from_type_hint(py_type)
107
106
  param = AnonPortDeclaration(
108
107
  name=None,
@@ -116,33 +115,30 @@ def _extract_port_decl(name: Optional[str], py_type: Any) -> AnonPortDeclaration
116
115
 
117
116
 
118
117
  def _extract_operand_decl(
119
- name: Optional[str], py_type: Any, qmodule: Optional[ModelStateContainer]
118
+ name: str | None, py_type: Any, qmodule: ModelStateContainer | None
120
119
  ) -> AnonQuantumOperandDeclaration:
121
- is_list = (get_origin(py_type) or py_type) is QCallableList
122
- is_generative = False
123
- if get_origin(py_type) is list:
124
- is_list = True
125
- is_generative = True
126
- py_type = version_portable_get_args(py_type)[0]
120
+ is_list = (get_origin(py_type) or py_type) is QCallableList or (
121
+ get_origin(py_type) or py_type
122
+ ) is QPermList
123
+ is_permutation = (get_origin(py_type) or py_type) is QPerm or (
124
+ get_origin(py_type) or py_type
125
+ ) is QPermList
127
126
  type_args = version_portable_get_args(py_type)
128
- if len(type_args) > 0 and isinstance(type_args[0], list): # Callable support
129
- type_args = tuple(type_args[0])
130
127
  param_decls = [_extract_operand_param(arg_type) for arg_type in type_args]
131
128
  param = AnonQuantumOperandDeclaration(
132
129
  name=name,
133
130
  positional_arg_declarations=_extract_positional_args(
134
131
  param_decls, qmodule=qmodule
135
132
  ),
133
+ permutation=is_permutation,
136
134
  is_list=is_list,
137
135
  )
138
- if is_generative:
139
- param = param.set_generative()
140
136
  if name is not None:
141
137
  param = param.rename(name)
142
138
  return param
143
139
 
144
140
 
145
- def _extract_operand_param(py_type: Any) -> tuple[Optional[str], Any]:
141
+ def _extract_operand_param(py_type: Any) -> tuple[str | None, Any]:
146
142
  if get_origin(py_type) is not Annotated:
147
143
  return None, py_type
148
144
 
@@ -164,7 +160,7 @@ def _unpacked_annotated(arg_0: Any, args: Any) -> _AnnotatedAlias:
164
160
  return Annotated.__class_getitem__((arg_0, *args)) # type:ignore[attr-defined]
165
161
 
166
162
 
167
- def _get_param_name(py_type_args: Any) -> Optional[str]:
163
+ def _get_param_name(py_type_args: Any) -> str | None:
168
164
  if isinstance(py_type_args[-1], str) and not isinstance(
169
165
  py_type_args[-1], (PortDeclarationDirection, TypeModifier)
170
166
  ):
@@ -189,20 +185,20 @@ def _validate_annotations(py_type_args: Any, py_type: Any) -> None:
189
185
 
190
186
  @overload
191
187
  def _extract_positional_args(
192
- args: Sequence[tuple[str, Any]], qmodule: Optional[ModelStateContainer]
188
+ args: Sequence[tuple[str, Any]], qmodule: ModelStateContainer | None
193
189
  ) -> Sequence[PositionalArg]:
194
190
  pass
195
191
 
196
192
 
197
193
  @overload
198
194
  def _extract_positional_args(
199
- args: Sequence[tuple[Optional[str], Any]], qmodule: Optional[ModelStateContainer]
195
+ args: Sequence[tuple[str | None, Any]], qmodule: ModelStateContainer | None
200
196
  ) -> Sequence[AnonPositionalArg]:
201
197
  pass
202
198
 
203
199
 
204
200
  def _extract_positional_args(
205
- args: Sequence[tuple[Optional[str], Any]], qmodule: Optional[ModelStateContainer]
201
+ args: Sequence[tuple[str | None, Any]], qmodule: ModelStateContainer | None
206
202
  ) -> Sequence[AnonPositionalArg]:
207
203
  result: list[AnonPositionalArg] = []
208
204
  for name, py_type in args:
@@ -222,18 +218,25 @@ def _extract_positional_args(
222
218
  elif is_qvar(py_type):
223
219
  result.append(_extract_port_decl(name, py_type))
224
220
  else:
221
+ if not issubclass(get_origin(py_type) or py_type, QCallable):
222
+ raise ClassiqValueError(
223
+ f"Unsupported type annotation {type_to_str(py_type)!r}"
224
+ )
225
225
  result.append(_extract_operand_decl(name, py_type, qmodule=qmodule))
226
226
  return result
227
227
 
228
228
 
229
229
  def infer_func_decl(
230
- py_func: Callable, qmodule: Optional[ModelStateContainer] = None
230
+ py_func: Callable,
231
+ qmodule: ModelStateContainer | None = None,
232
+ permutation: bool = False,
231
233
  ) -> NamedParamsQuantumFunctionDeclaration:
232
234
  return NamedParamsQuantumFunctionDeclaration(
233
235
  name=unmangle_keyword(py_func.__name__),
234
236
  positional_arg_declarations=_extract_positional_args(
235
237
  list(py_func.__annotations__.items()), qmodule=qmodule
236
238
  ),
239
+ permutation=permutation,
237
240
  )
238
241
 
239
242
 
@@ -1,6 +1,6 @@
1
1
  from collections import defaultdict
2
2
  from collections.abc import Sequence
3
- from typing import TYPE_CHECKING, Union
3
+ from typing import TYPE_CHECKING
4
4
 
5
5
  from classiq.interface.generator.constant import Constant
6
6
  from classiq.interface.generator.types.compilation_metadata import CompilationMetadata
@@ -40,7 +40,7 @@ class ModelStateContainer:
40
40
 
41
41
  def user_types(
42
42
  self,
43
- ) -> Sequence[Union[EnumDeclaration, StructDeclaration, QStructDeclaration]]:
43
+ ) -> Sequence[EnumDeclaration | StructDeclaration | QStructDeclaration]:
44
44
  type_decls = [
45
45
  t
46
46
  for t in self.type_decls.values()
@@ -1,5 +1,4 @@
1
1
  from collections.abc import Mapping
2
- from typing import Optional, Union
3
2
 
4
3
  from classiq.interface.constants import DEFAULT_DECIMAL_PRECISION
5
4
  from classiq.interface.exceptions import ClassiqInternalError
@@ -93,9 +92,9 @@ from classiq.qmod.semantics.annotation.call_annotation import resolve_function_c
93
92
  class DSLPrettyPrinter(ModelVisitor):
94
93
  def __init__(
95
94
  self,
96
- decimal_precision: Optional[int] = DEFAULT_DECIMAL_PRECISION,
95
+ decimal_precision: int | None = DEFAULT_DECIMAL_PRECISION,
97
96
  emit_open_lib_functions: bool = False,
98
- compilation_metadata: Optional[dict[str, CompilationMetadata]] = None,
97
+ compilation_metadata: dict[str, CompilationMetadata] | None = None,
99
98
  ) -> None:
100
99
  self._level = 0
101
100
  self._decimal_precision = decimal_precision
@@ -145,19 +144,30 @@ class DSLPrettyPrinter(ModelVisitor):
145
144
  )
146
145
  return f"({positional_args})"
147
146
 
148
- def _get_unchecked_string(self, func_decl: QuantumFunctionDeclaration) -> str:
149
- if func_decl.name not in self._compilation_metadata:
147
+ def _get_decorators(self, func: str) -> str:
148
+ if func not in self._compilation_metadata:
150
149
  return ""
151
- unchecked = self._compilation_metadata[func_decl.name].unchecked
152
- if len(unchecked) == 0:
153
- return ""
154
- return f" unchecked ({', '.join(unchecked)})\n"
150
+
151
+ decorators = ""
152
+ metadata = self._compilation_metadata[func]
153
+
154
+ if metadata.disable_perm_check:
155
+ decorators += "@disable_perm_check\n"
156
+
157
+ if metadata.disable_const_checks:
158
+ if metadata.disable_const_checks is True:
159
+ decorators += "@disable_const_checks\n"
160
+ else:
161
+ decorators += f"@disable_const_checks({', '.join(metadata.disable_const_checks)})\n"
162
+
163
+ return decorators
155
164
 
156
165
  def visit_QuantumFunctionDeclaration(
157
166
  self, func_decl: QuantumFunctionDeclaration
158
167
  ) -> str:
159
- unchecked = self._get_unchecked_string(func_decl)
160
- return f"qfunc {func_decl.name}{self._visit_arg_decls(func_decl)}{unchecked}"
168
+ decorators = self._get_decorators(func_decl.name)
169
+ function_type = "qperm" if func_decl.permutation else "qfunc"
170
+ return f"{decorators}{function_type} {func_decl.name}{self._visit_arg_decls(func_decl)}"
161
171
 
162
172
  def visit_EnumDeclaration(self, enum_decl: EnumDeclaration) -> str:
163
173
  return f"enum {enum_decl.name} {{\n{self._visit_members(enum_decl.members)}}}\n"
@@ -178,7 +188,7 @@ class DSLPrettyPrinter(ModelVisitor):
178
188
  return f"qstruct {qstruct_decl.name} {{\n{self._visit_variables(qstruct_decl.fields)}}}\n"
179
189
 
180
190
  def _visit_variables(
181
- self, variables: Mapping[str, Union[ConcreteClassicalType, ConcreteQuantumType]]
191
+ self, variables: Mapping[str, ConcreteClassicalType | ConcreteQuantumType]
182
192
  ) -> str:
183
193
  self._level += 1
184
194
  variables_str = "".join(
@@ -191,7 +201,7 @@ class DSLPrettyPrinter(ModelVisitor):
191
201
  def visit_AnonPortDeclaration(self, port_decl: AnonPortDeclaration) -> str:
192
202
  modifier_str = (
193
203
  f"{port_decl.type_modifier} "
194
- if port_decl.type_modifier in [TypeModifier.Const, TypeModifier.Permutable]
204
+ if port_decl.type_modifier is TypeModifier.Const
195
205
  else ""
196
206
  )
197
207
  dir_str = (
@@ -265,7 +275,8 @@ class DSLPrettyPrinter(ModelVisitor):
265
275
  self, op_decl: AnonQuantumOperandDeclaration
266
276
  ) -> str:
267
277
  param_name = f"{op_decl.name}: " if op_decl.name is not None else ""
268
- return f"{param_name}qfunc{[] if op_decl.is_list else ''} {self._visit_arg_decls(op_decl)}"
278
+ function_type = "qperm" if op_decl.permutation else "qfunc"
279
+ return f"{param_name}{function_type}{[] if op_decl.is_list else ''} {self._visit_arg_decls(op_decl)}"
269
280
 
270
281
  def visit_QuantumOperandDeclaration(
271
282
  self, op_decl: QuantumOperandDeclaration
@@ -1,8 +1,7 @@
1
1
  import ast
2
2
  import re
3
- from collections.abc import Mapping
3
+ from collections.abc import Callable, Mapping
4
4
  from dataclasses import dataclass
5
- from typing import Callable
6
5
 
7
6
  import numpy as np
8
7
 
@@ -120,7 +119,10 @@ class ASTToQMODCode(ast.NodeVisitor):
120
119
  return f"[{elements}]"
121
120
 
122
121
  def visit_Subscript(self, node: ast.Subscript) -> str:
123
- return f"{self.visit(node.value)}[{_remove_redundant_parentheses(self.visit(node.slice))}]"
122
+ if not isinstance(node.value, ast.List):
123
+ return f"{self.visit(node.value)}[{_remove_redundant_parentheses(self.visit(node.slice))}]"
124
+ self.symbolic_imports["subscript"] = 1
125
+ return f"subscript({self.visit(node.value)}, {_remove_redundant_parentheses(self.visit(node.slice))})"
124
126
 
125
127
  def visit_Slice(self, node: ast.Slice) -> str:
126
128
  if node.lower is None or node.upper is None or node.step is not None:
@@ -1,5 +1,5 @@
1
1
  from collections.abc import Mapping
2
- from typing import Optional, Union, cast
2
+ from typing import cast
3
3
 
4
4
  import black
5
5
 
@@ -108,7 +108,7 @@ class VariableDeclarationAssignment(Visitor):
108
108
 
109
109
  def visit_QuantumBitvector(
110
110
  self, qtype: QuantumBitvector
111
- ) -> tuple[str, Optional[list[str]]]:
111
+ ) -> tuple[str, list[str] | None]:
112
112
  self.pretty_printer._imports["QArray"] = 1
113
113
 
114
114
  element_type = self.pretty_printer.visit(qtype.element_type)
@@ -118,7 +118,7 @@ class VariableDeclarationAssignment(Visitor):
118
118
 
119
119
  def visit_QuantumNumeric(
120
120
  self, qtype: QuantumNumeric
121
- ) -> tuple[str, Optional[list[str]]]:
121
+ ) -> tuple[str, list[str] | None]:
122
122
  self.pretty_printer._imports["QNum"] = 1
123
123
  return "QNum", self.pretty_printer._get_qnum_properties(qtype)
124
124
 
@@ -130,12 +130,12 @@ class PythonPrettyPrinter(ModelVisitor):
130
130
  def __init__(self, decimal_precision: int = DEFAULT_DECIMAL_PRECISION) -> None:
131
131
  self._level = 0
132
132
  self._decimal_precision = decimal_precision
133
- self._imports = {"qfunc": 1}
133
+ self._imports: dict[str, int] = {}
134
134
  self._import_enum = False
135
135
  self._import_dataclass = False
136
136
  self._import_annotated = False
137
137
  self._symbolic_imports: dict[str, int] = dict()
138
- self._functions: Optional[Mapping[str, QuantumFunctionDeclaration]] = None
138
+ self._functions: Mapping[str, QuantumFunctionDeclaration] | None = None
139
139
  self._compilation_metadata: dict[str, CompilationMetadata] = dict()
140
140
 
141
141
  def visit(self, node: NodeType) -> str:
@@ -204,16 +204,33 @@ class PythonPrettyPrinter(ModelVisitor):
204
204
  )
205
205
 
206
206
  def _get_qfunc_decorator(self, func_decl: QuantumFunctionDeclaration) -> str:
207
- no_unchecked_decorator = "@qfunc"
207
+ if func_decl.permutation:
208
+ decorator = "@qperm"
209
+ self._imports["qperm"] = 1
210
+ else:
211
+ decorator = "@qfunc"
212
+ self._imports["qfunc"] = 1
213
+
208
214
  if func_decl.name not in self._compilation_metadata:
209
- return no_unchecked_decorator
210
- unchecked = self._compilation_metadata[func_decl.name].unchecked
211
- if len(unchecked) == 0:
212
- return no_unchecked_decorator
215
+ return decorator
216
+
217
+ metadata = self._compilation_metadata[func_decl.name]
218
+
219
+ decorator_params: list[str] = []
220
+ if metadata.disable_perm_check:
221
+ decorator_params.append("disable_perm_check=True")
213
222
 
214
- unchecked_modifiers = (f'"{modifier}"' for modifier in unchecked)
215
- unchecked_list = f"[{', '.join(unchecked_modifiers)}]"
216
- return no_unchecked_decorator + f" (unchecked={unchecked_list})"
223
+ if metadata.disable_const_checks:
224
+ if metadata.disable_const_checks is True:
225
+ value = "True"
226
+ else:
227
+ value = f"[{', '.join(f'{param!r}' for param in metadata.disable_const_checks)}]"
228
+ decorator_params.append(f"disable_const_checks={value}")
229
+
230
+ if decorator_params:
231
+ return f"{decorator}({', '.join(decorator_params)})"
232
+ else:
233
+ return decorator
217
234
 
218
235
  def visit_QuantumFunctionDeclaration(
219
236
  self, func_decl: QuantumFunctionDeclaration
@@ -243,7 +260,7 @@ class PythonPrettyPrinter(ModelVisitor):
243
260
  return f"class {qstruct_decl.name}(QStruct):\n{self._visit_variables(qstruct_decl.fields)}\n"
244
261
 
245
262
  def _visit_variables(
246
- self, variables: Mapping[str, Union[ConcreteClassicalType, ConcreteQuantumType]]
263
+ self, variables: Mapping[str, ConcreteClassicalType | ConcreteQuantumType]
247
264
  ) -> str:
248
265
  self._level += 1
249
266
  variables_str = "".join(
@@ -262,7 +279,7 @@ class PythonPrettyPrinter(ModelVisitor):
262
279
  if port_decl.direction is not PortDeclarationDirection.Inout:
263
280
  self._imports[port_decl.direction.name] = 1
264
281
  var_type = f"{port_decl.direction.name}[{var_type}]"
265
- if port_decl.type_modifier in [TypeModifier.Const, TypeModifier.Permutable]:
282
+ if port_decl.type_modifier is TypeModifier.Const:
266
283
  self._imports[port_decl.type_modifier.name] = 1
267
284
  var_type = f"{port_decl.type_modifier.name}[{var_type}]"
268
285
  return var_type
@@ -394,7 +411,12 @@ class PythonPrettyPrinter(ModelVisitor):
394
411
  def visit_AnonQuantumOperandDeclaration(
395
412
  self, op_decl: AnonQuantumOperandDeclaration, no_param: bool = False
396
413
  ) -> str:
397
- qcallable_identifier = "QCallableList" if op_decl.is_list else "QCallable"
414
+ qcallable_identifier = {
415
+ (False, False): "QCallable",
416
+ (False, True): "QCallableList",
417
+ (True, False): "QPerm",
418
+ (True, True): "QPermList",
419
+ }[(op_decl.permutation, op_decl.is_list)]
398
420
  self._imports[qcallable_identifier] = 1
399
421
  args = ", ".join(
400
422
  self._visit_operand_arg_decl(arg_decl)
@@ -494,7 +516,7 @@ class PythonPrettyPrinter(ModelVisitor):
494
516
  return f"{self._indent}block({self._visit_body(block.statements)})\n"
495
517
 
496
518
  def _visit_body(
497
- self, body: StatementBlock, operand_arguments: Optional[list[str]] = None
519
+ self, body: StatementBlock, operand_arguments: list[str] | None = None
498
520
  ) -> str:
499
521
  if len(body) == 0:
500
522
  return "lambda: []"
@@ -5,7 +5,6 @@ from typing import (
5
5
  Any,
6
6
  ForwardRef,
7
7
  Literal,
8
- Optional,
9
8
  get_args,
10
9
  get_origin,
11
10
  )
@@ -15,6 +14,7 @@ from classiq.interface.generator.expressions.expression import Expression
15
14
  from classiq.interface.generator.functions.classical_type import (
16
15
  Bool,
17
16
  ClassicalArray,
17
+ ClassicalTuple,
18
18
  Integer,
19
19
  Real,
20
20
  )
@@ -22,7 +22,7 @@ from classiq.interface.generator.functions.concrete_types import ConcreteClassic
22
22
  from classiq.interface.generator.functions.type_name import Enum, Struct, TypeName
23
23
 
24
24
  from classiq.qmod.cparam import CArray, CBool, CInt, CReal
25
- from classiq.qmod.utilities import version_portable_get_args
25
+ from classiq.qmod.utilities import type_to_str, version_portable_get_args
26
26
 
27
27
  CARRAY_ERROR_MESSAGE = (
28
28
  "CArray accepts one or two generic parameters in the form "
@@ -30,10 +30,23 @@ CARRAY_ERROR_MESSAGE = (
30
30
  )
31
31
 
32
32
 
33
+ def _has_struct_or_enum(classical_type: ConcreteClassicalType) -> bool:
34
+ if isinstance(classical_type, TypeName):
35
+ return True
36
+ if isinstance(classical_type, ClassicalArray):
37
+ return _has_struct_or_enum(classical_type.element_type)
38
+ if isinstance(classical_type, ClassicalTuple):
39
+ return any(
40
+ _has_struct_or_enum(element_type)
41
+ for element_type in classical_type.element_types
42
+ )
43
+ return False
44
+
45
+
33
46
  class PythonClassicalType:
34
47
  def convert(
35
48
  self, py_type: type, nested: bool = False
36
- ) -> Optional[ConcreteClassicalType]:
49
+ ) -> ConcreteClassicalType | None:
37
50
  if py_type is int:
38
51
  return Integer().set_generative()
39
52
  elif py_type is CInt:
@@ -47,21 +60,35 @@ class PythonClassicalType:
47
60
  elif py_type is CBool:
48
61
  return Bool()
49
62
  elif get_origin(py_type) is list:
50
- element_type = self.convert(get_args(py_type)[0], nested=True)
51
- if element_type is not None:
52
- return ClassicalArray(element_type=element_type).set_generative()
63
+ element_py_type = get_args(py_type)[0]
64
+ element_type = self.convert(element_py_type, nested=True)
65
+ if element_type is None:
66
+ return None
67
+ if not element_type.is_generative and not _has_struct_or_enum(element_type):
68
+ raise ClassiqValueError(
69
+ f"Invalid type annotation: 'list' is generative but "
70
+ f"{type_to_str(element_py_type)!r} is declarative"
71
+ )
72
+ return ClassicalArray(element_type=element_type).set_generative()
53
73
  elif get_origin(py_type) is CArray:
54
74
  array_args = version_portable_get_args(py_type)
55
75
  if len(array_args) == 1:
56
- return ClassicalArray(
57
- element_type=self.convert(array_args[0], nested=True)
58
- )
76
+ length = None
59
77
  elif len(array_args) == 2:
60
- return ClassicalArray(
61
- element_type=self.convert(array_args[0], nested=True),
62
- length=Expression(expr=get_type_hint_expr(array_args[1])),
78
+ length = Expression(expr=get_type_hint_expr(array_args[1]))
79
+ else:
80
+ raise ClassiqValueError(CARRAY_ERROR_MESSAGE)
81
+ element_type = self.convert(array_args[0], nested=True)
82
+ if element_type is None:
83
+ return None
84
+ if element_type.is_generative and not _has_struct_or_enum(element_type):
85
+ raise ClassiqValueError(
86
+ f"Invalid type annotation: 'CArray' is declarative but "
87
+ f"{type_to_str(array_args[0])!r} is generative"
63
88
  )
64
- raise ClassiqValueError(CARRAY_ERROR_MESSAGE)
89
+ return ClassicalArray(
90
+ element_type=self.convert(array_args[0], nested=True), length=length
91
+ )
65
92
  elif inspect.isclass(py_type) and dataclasses.is_dataclass(py_type):
66
93
  return self.register_struct(py_type)
67
94
  elif inspect.isclass(py_type) and isinstance(py_type, EnumMeta):