classiq 0.93.0__py3-none-any.whl → 0.99.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 (315) hide show
  1. classiq/__init__.py +11 -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 +31 -142
  5. classiq/_internals/async_utils.py +4 -7
  6. classiq/_internals/authentication/auth0.py +41 -15
  7. classiq/_internals/authentication/authorization_code.py +9 -0
  8. classiq/_internals/authentication/authorization_flow.py +41 -0
  9. classiq/_internals/authentication/device.py +33 -52
  10. classiq/_internals/authentication/hybrid_flow.py +19 -0
  11. classiq/_internals/authentication/password_manager.py +13 -13
  12. classiq/_internals/authentication/token_manager.py +9 -9
  13. classiq/_internals/client.py +17 -44
  14. classiq/_internals/config.py +19 -5
  15. classiq/_internals/help.py +1 -2
  16. classiq/_internals/host_checker.py +3 -3
  17. classiq/_internals/jobs.py +14 -14
  18. classiq/_internals/type_validation.py +3 -3
  19. classiq/analyzer/analyzer.py +18 -18
  20. classiq/analyzer/rb.py +17 -8
  21. classiq/analyzer/show_interactive_hack.py +1 -1
  22. classiq/applications/__init__.py +2 -2
  23. classiq/applications/chemistry/__init__.py +0 -30
  24. classiq/applications/chemistry/op_utils.py +4 -4
  25. classiq/applications/chemistry/problems.py +3 -3
  26. classiq/applications/chemistry/ucc.py +1 -2
  27. classiq/applications/chemistry/z2_symmetries.py +4 -4
  28. classiq/applications/combinatorial_helpers/allowed_constraints.py +1 -3
  29. classiq/applications/combinatorial_helpers/arithmetic/arithmetic_expression.py +2 -1
  30. classiq/applications/combinatorial_helpers/combinatorial_problem_utils.py +2 -2
  31. classiq/applications/combinatorial_helpers/encoding_mapping.py +2 -3
  32. classiq/applications/combinatorial_helpers/encoding_utils.py +2 -2
  33. classiq/applications/combinatorial_helpers/optimization_model.py +3 -4
  34. classiq/applications/combinatorial_helpers/pauli_helpers/pauli_sparsing.py +2 -2
  35. classiq/applications/combinatorial_helpers/pyomo_utils.py +8 -8
  36. classiq/applications/combinatorial_helpers/sympy_utils.py +1 -3
  37. classiq/applications/combinatorial_helpers/transformations/encoding.py +3 -3
  38. classiq/applications/combinatorial_helpers/transformations/fixed_variables.py +1 -2
  39. classiq/applications/combinatorial_optimization/combinatorial_optimization_config.py +2 -3
  40. classiq/applications/combinatorial_optimization/combinatorial_optimization_model_constructor.py +4 -6
  41. classiq/applications/combinatorial_optimization/combinatorial_problem.py +15 -10
  42. classiq/applications/hamiltonian/pauli_decomposition.py +6 -4
  43. classiq/applications/iqae/iqae.py +14 -11
  44. classiq/applications/qnn/datasets/dataset_base_classes.py +6 -6
  45. classiq/applications/qnn/datasets/dataset_parity.py +6 -6
  46. classiq/applications/qnn/gradients/simple_quantum_gradient.py +1 -1
  47. classiq/applications/qnn/qlayer.py +9 -8
  48. classiq/applications/qnn/torch_utils.py +5 -6
  49. classiq/applications/qnn/types.py +2 -1
  50. classiq/applications/qsp/__init__.py +20 -2
  51. classiq/applications/qsp/qsp.py +238 -10
  52. classiq/applications/qsvm/qsvm_data_generation.py +1 -2
  53. classiq/evaluators/classical_expression.py +0 -4
  54. classiq/evaluators/parameter_types.py +10 -8
  55. classiq/evaluators/qmod_annotated_expression.py +31 -26
  56. classiq/evaluators/qmod_expression_visitors/qmod_expression_evaluator.py +14 -14
  57. classiq/evaluators/qmod_expression_visitors/qmod_expression_simplifier.py +2 -1
  58. classiq/evaluators/qmod_expression_visitors/sympy_wrappers.py +8 -8
  59. classiq/evaluators/qmod_node_evaluators/binary_op_evaluation.py +4 -4
  60. classiq/evaluators/qmod_node_evaluators/classical_function_evaluation.py +14 -4
  61. classiq/evaluators/qmod_node_evaluators/list_evaluation.py +2 -2
  62. classiq/evaluators/qmod_node_evaluators/numeric_attrs_utils.py +3 -3
  63. classiq/evaluators/qmod_node_evaluators/subscript_evaluation.py +9 -9
  64. classiq/evaluators/qmod_node_evaluators/utils.py +6 -6
  65. classiq/evaluators/qmod_type_inference/classical_type_inference.py +9 -10
  66. classiq/evaluators/qmod_type_inference/quantum_type_inference.py +5 -5
  67. classiq/execution/__init__.py +0 -3
  68. classiq/execution/execution_session.py +28 -21
  69. classiq/execution/jobs.py +26 -26
  70. classiq/execution/qnn.py +1 -2
  71. classiq/execution/user_budgets.py +71 -37
  72. classiq/executor.py +1 -3
  73. classiq/interface/_version.py +1 -1
  74. classiq/interface/analyzer/analysis_params.py +4 -4
  75. classiq/interface/analyzer/cytoscape_graph.py +3 -3
  76. classiq/interface/analyzer/result.py +4 -4
  77. classiq/interface/ast_node.py +3 -3
  78. classiq/interface/backend/backend_preferences.py +26 -50
  79. classiq/interface/backend/ionq/ionq_quantum_program.py +5 -5
  80. classiq/interface/backend/provider_config/__init__.py +0 -0
  81. classiq/interface/backend/provider_config/provider_config.py +8 -0
  82. classiq/interface/backend/provider_config/providers/__init__.py +0 -0
  83. classiq/interface/backend/provider_config/providers/alice_bob.py +47 -0
  84. classiq/interface/backend/provider_config/providers/aqt.py +16 -0
  85. classiq/interface/backend/provider_config/providers/azure.py +37 -0
  86. classiq/interface/backend/provider_config/providers/braket.py +39 -0
  87. classiq/interface/backend/provider_config/providers/ibm.py +26 -0
  88. classiq/interface/backend/provider_config/providers/ionq.py +22 -0
  89. classiq/interface/backend/quantum_backend_providers.py +20 -2
  90. classiq/interface/chemistry/ansatz_library.py +3 -5
  91. classiq/interface/chemistry/operator.py +3 -3
  92. classiq/interface/combinatorial_optimization/examples/knapsack.py +2 -4
  93. classiq/interface/combinatorial_optimization/examples/tsp_digraph.py +1 -2
  94. classiq/interface/compression_utils.py +2 -3
  95. classiq/interface/debug_info/debug_info.py +8 -7
  96. classiq/interface/exceptions.py +6 -7
  97. classiq/interface/execution/primitives.py +6 -6
  98. classiq/interface/executor/estimate_cost.py +1 -1
  99. classiq/interface/executor/execution_preferences.py +3 -5
  100. classiq/interface/executor/execution_request.py +10 -10
  101. classiq/interface/executor/execution_result.py +1 -2
  102. classiq/interface/executor/quantum_code.py +8 -8
  103. classiq/interface/executor/result.py +28 -18
  104. classiq/interface/executor/user_budget.py +25 -17
  105. classiq/interface/executor/vqe_result.py +5 -6
  106. classiq/interface/generator/ansatz_library.py +6 -8
  107. classiq/interface/generator/application_apis/__init__.py +0 -3
  108. classiq/interface/generator/arith/arithmetic.py +2 -2
  109. classiq/interface/generator/arith/arithmetic_arg_type_validator.py +2 -3
  110. classiq/interface/generator/arith/arithmetic_expression_abc.py +4 -5
  111. classiq/interface/generator/arith/arithmetic_expression_parser.py +11 -4
  112. classiq/interface/generator/arith/arithmetic_expression_validator.py +12 -15
  113. classiq/interface/generator/arith/arithmetic_operations.py +4 -6
  114. classiq/interface/generator/arith/arithmetic_param_getters.py +70 -107
  115. classiq/interface/generator/arith/arithmetic_result_builder.py +4 -4
  116. classiq/interface/generator/arith/ast_node_rewrite.py +8 -4
  117. classiq/interface/generator/arith/binary_ops.py +15 -40
  118. classiq/interface/generator/arith/logical_ops.py +2 -3
  119. classiq/interface/generator/arith/number_utils.py +2 -2
  120. classiq/interface/generator/arith/register_user_input.py +3 -3
  121. classiq/interface/generator/arith/unary_ops.py +2 -2
  122. classiq/interface/generator/circuit_code/circuit_code.py +8 -10
  123. classiq/interface/generator/circuit_code/types_and_constants.py +1 -1
  124. classiq/interface/generator/complex_type.py +2 -2
  125. classiq/interface/generator/copy.py +1 -3
  126. classiq/interface/generator/expressions/atomic_expression_functions.py +0 -5
  127. classiq/interface/generator/expressions/evaluated_expression.py +2 -3
  128. classiq/interface/generator/expressions/expression.py +2 -2
  129. classiq/interface/generator/expressions/proxies/classical/classical_array_proxy.py +4 -7
  130. classiq/interface/generator/function_param_list.py +0 -40
  131. classiq/interface/generator/function_params.py +5 -6
  132. classiq/interface/generator/functions/classical_function_declaration.py +2 -2
  133. classiq/interface/generator/functions/classical_type.py +3 -3
  134. classiq/interface/generator/functions/type_modifier.py +0 -15
  135. classiq/interface/generator/functions/type_name.py +2 -2
  136. classiq/interface/generator/generated_circuit_data.py +14 -18
  137. classiq/interface/generator/hamiltonian_evolution/exponentiation.py +2 -4
  138. classiq/interface/generator/hardware/hardware_data.py +8 -8
  139. classiq/interface/generator/hardware_efficient_ansatz.py +9 -9
  140. classiq/interface/generator/mcu.py +3 -3
  141. classiq/interface/generator/mcx.py +3 -3
  142. classiq/interface/generator/model/constraints.py +34 -5
  143. classiq/interface/generator/model/preferences/preferences.py +15 -21
  144. classiq/interface/generator/model/quantum_register.py +7 -10
  145. classiq/interface/generator/noise_properties.py +3 -7
  146. classiq/interface/generator/parameters.py +1 -1
  147. classiq/interface/generator/partitioned_register.py +1 -2
  148. classiq/interface/generator/preferences/qasm_to_qmod_params.py +11 -0
  149. classiq/interface/generator/quantum_function_call.py +9 -12
  150. classiq/interface/generator/quantum_program.py +10 -23
  151. classiq/interface/generator/range_types.py +3 -3
  152. classiq/interface/generator/slice_parsing_utils.py +4 -5
  153. classiq/interface/generator/standard_gates/standard_gates.py +2 -4
  154. classiq/interface/generator/synthesis_execution_parameter.py +1 -3
  155. classiq/interface/generator/synthesis_metadata/synthesis_duration.py +9 -0
  156. classiq/interface/generator/synthesis_metadata/synthesis_execution_data.py +2 -3
  157. classiq/interface/generator/transpiler_basis_gates.py +12 -4
  158. classiq/interface/generator/types/builtin_enum_declarations.py +0 -145
  159. classiq/interface/generator/types/compilation_metadata.py +12 -1
  160. classiq/interface/generator/types/enum_declaration.py +2 -1
  161. classiq/interface/generator/validations/flow_graph.py +3 -3
  162. classiq/interface/generator/visitor.py +10 -12
  163. classiq/interface/hardware.py +2 -3
  164. classiq/interface/helpers/classproperty.py +2 -2
  165. classiq/interface/helpers/custom_encoders.py +2 -1
  166. classiq/interface/helpers/custom_pydantic_types.py +1 -1
  167. classiq/interface/helpers/text_utils.py +1 -4
  168. classiq/interface/ide/visual_model.py +6 -5
  169. classiq/interface/interface_version.py +1 -1
  170. classiq/interface/jobs.py +3 -3
  171. classiq/interface/model/allocate.py +4 -4
  172. classiq/interface/model/block.py +6 -2
  173. classiq/interface/model/bounds.py +3 -3
  174. classiq/interface/model/classical_if.py +4 -0
  175. classiq/interface/model/control.py +8 -1
  176. classiq/interface/model/inplace_binary_operation.py +2 -2
  177. classiq/interface/model/invert.py +4 -0
  178. classiq/interface/model/model.py +4 -4
  179. classiq/interface/model/model_visitor.py +40 -1
  180. classiq/interface/model/parameter.py +1 -3
  181. classiq/interface/model/port_declaration.py +1 -1
  182. classiq/interface/model/power.py +4 -0
  183. classiq/interface/model/quantum_expressions/quantum_expression.py +1 -2
  184. classiq/interface/model/quantum_function_call.py +3 -6
  185. classiq/interface/model/quantum_function_declaration.py +1 -0
  186. classiq/interface/model/quantum_lambda_function.py +4 -4
  187. classiq/interface/model/quantum_statement.py +11 -4
  188. classiq/interface/model/quantum_type.py +14 -14
  189. classiq/interface/model/repeat.py +4 -0
  190. classiq/interface/model/skip_control.py +4 -0
  191. classiq/interface/model/validation_handle.py +2 -3
  192. classiq/interface/model/variable_declaration_statement.py +2 -2
  193. classiq/interface/model/within_apply_operation.py +4 -0
  194. classiq/interface/pretty_print/expression_to_qmod.py +3 -4
  195. classiq/interface/server/routes.py +0 -16
  196. classiq/interface/source_reference.py +3 -4
  197. classiq/model_expansions/arithmetic.py +11 -7
  198. classiq/model_expansions/arithmetic_compute_result_attrs.py +30 -27
  199. classiq/model_expansions/capturing/captured_vars.py +3 -3
  200. classiq/model_expansions/capturing/mangling_utils.py +1 -2
  201. classiq/model_expansions/closure.py +12 -11
  202. classiq/model_expansions/function_builder.py +14 -6
  203. classiq/model_expansions/generative_functions.py +7 -12
  204. classiq/model_expansions/interpreters/base_interpreter.py +3 -7
  205. classiq/model_expansions/interpreters/frontend_generative_interpreter.py +2 -1
  206. classiq/model_expansions/interpreters/generative_interpreter.py +5 -3
  207. classiq/model_expansions/quantum_operations/allocate.py +4 -4
  208. classiq/model_expansions/quantum_operations/assignment_result_processor.py +2 -4
  209. classiq/model_expansions/quantum_operations/call_emitter.py +31 -37
  210. classiq/model_expansions/quantum_operations/declarative_call_emitter.py +2 -2
  211. classiq/model_expansions/quantum_operations/emitter.py +3 -5
  212. classiq/model_expansions/quantum_operations/expression_evaluator.py +3 -3
  213. classiq/model_expansions/quantum_operations/skip_control_verifier.py +1 -2
  214. classiq/model_expansions/quantum_operations/variable_decleration.py +2 -2
  215. classiq/model_expansions/scope.py +7 -7
  216. classiq/model_expansions/scope_initialization.py +4 -0
  217. classiq/model_expansions/visitors/symbolic_param_inference.py +6 -6
  218. classiq/model_expansions/visitors/uncomputation_signature_inference.py +328 -0
  219. classiq/model_expansions/visitors/variable_references.py +15 -14
  220. classiq/open_library/functions/__init__.py +28 -11
  221. classiq/open_library/functions/amplitude_loading.py +81 -0
  222. classiq/open_library/functions/discrete_sine_cosine_transform.py +5 -5
  223. classiq/open_library/functions/grover.py +8 -10
  224. classiq/open_library/functions/lcu.py +47 -18
  225. classiq/open_library/functions/modular_exponentiation.py +93 -8
  226. classiq/open_library/functions/qsvt.py +66 -79
  227. classiq/open_library/functions/qsvt_temp.py +536 -0
  228. classiq/open_library/functions/state_preparation.py +130 -27
  229. classiq/qmod/__init__.py +6 -4
  230. classiq/qmod/builtins/classical_execution_primitives.py +4 -23
  231. classiq/qmod/builtins/classical_functions.py +1 -42
  232. classiq/qmod/builtins/enums.py +15 -153
  233. classiq/qmod/builtins/functions/__init__.py +9 -18
  234. classiq/qmod/builtins/functions/allocation.py +25 -4
  235. classiq/qmod/builtins/functions/arithmetic.py +22 -27
  236. classiq/qmod/builtins/functions/exponentiation.py +51 -2
  237. classiq/qmod/builtins/functions/mcx_func.py +7 -0
  238. classiq/qmod/builtins/functions/standard_gates.py +46 -27
  239. classiq/qmod/builtins/operations.py +165 -79
  240. classiq/qmod/builtins/structs.py +24 -91
  241. classiq/qmod/cfunc.py +3 -2
  242. classiq/qmod/classical_function.py +2 -1
  243. classiq/qmod/cparam.py +2 -8
  244. classiq/qmod/create_model_function.py +7 -7
  245. classiq/qmod/declaration_inferrer.py +33 -30
  246. classiq/qmod/expression_query.py +7 -4
  247. classiq/qmod/model_state_container.py +2 -2
  248. classiq/qmod/native/pretty_printer.py +25 -14
  249. classiq/qmod/pretty_print/expression_to_python.py +5 -3
  250. classiq/qmod/pretty_print/pretty_printer.py +39 -17
  251. classiq/qmod/python_classical_type.py +40 -13
  252. classiq/qmod/qfunc.py +124 -19
  253. classiq/qmod/qmod_constant.py +2 -2
  254. classiq/qmod/qmod_parameter.py +5 -2
  255. classiq/qmod/qmod_variable.py +47 -46
  256. classiq/qmod/quantum_callable.py +18 -13
  257. classiq/qmod/quantum_expandable.py +31 -26
  258. classiq/qmod/quantum_function.py +84 -36
  259. classiq/qmod/semantics/annotation/call_annotation.py +5 -5
  260. classiq/qmod/semantics/error_manager.py +12 -14
  261. classiq/qmod/semantics/lambdas.py +1 -2
  262. classiq/qmod/semantics/validation/types_validation.py +1 -2
  263. classiq/qmod/symbolic.py +2 -4
  264. classiq/qmod/utilities.py +13 -20
  265. classiq/qmod/write_qmod.py +3 -4
  266. classiq/quantum_program.py +1 -3
  267. classiq/synthesis.py +11 -7
  268. {classiq-0.93.0.dist-info → classiq-0.99.0.dist-info}/METADATA +2 -3
  269. {classiq-0.93.0.dist-info → classiq-0.99.0.dist-info}/RECORD +271 -299
  270. {classiq-0.93.0.dist-info → classiq-0.99.0.dist-info}/WHEEL +1 -1
  271. classiq/applications/chemistry/ansatz_parameters.py +0 -29
  272. classiq/applications/chemistry/chemistry_execution_parameters.py +0 -16
  273. classiq/applications/chemistry/chemistry_model_constructor.py +0 -532
  274. classiq/applications/chemistry/ground_state_problem.py +0 -42
  275. classiq/applications/qsvm/__init__.py +0 -8
  276. classiq/applications/qsvm/qsvm.py +0 -11
  277. classiq/evaluators/qmod_expression_visitors/qmod_expression_bwc.py +0 -129
  278. classiq/execution/iqcc.py +0 -128
  279. classiq/interface/applications/qsvm.py +0 -117
  280. classiq/interface/chemistry/elements.py +0 -120
  281. classiq/interface/chemistry/fermionic_operator.py +0 -208
  282. classiq/interface/chemistry/ground_state_problem.py +0 -132
  283. classiq/interface/chemistry/ground_state_result.py +0 -8
  284. classiq/interface/chemistry/molecule.py +0 -71
  285. classiq/interface/execution/iqcc.py +0 -44
  286. classiq/interface/generator/application_apis/chemistry_declarations.py +0 -69
  287. classiq/interface/generator/application_apis/entangler_declarations.py +0 -29
  288. classiq/interface/generator/application_apis/qsvm_declarations.py +0 -6
  289. classiq/interface/generator/chemistry_function_params.py +0 -50
  290. classiq/interface/generator/entangler_params.py +0 -72
  291. classiq/interface/generator/entanglers.py +0 -14
  292. classiq/interface/generator/hamiltonian_evolution/qdrift.py +0 -27
  293. classiq/interface/generator/hartree_fock.py +0 -26
  294. classiq/interface/generator/hva.py +0 -22
  295. classiq/interface/generator/linear_pauli_rotations.py +0 -92
  296. classiq/interface/generator/qft.py +0 -37
  297. classiq/interface/generator/qsvm.py +0 -96
  298. classiq/interface/generator/state_preparation/__init__.py +0 -14
  299. classiq/interface/generator/state_preparation/bell_state_preparation.py +0 -27
  300. classiq/interface/generator/state_preparation/computational_basis_state_preparation.py +0 -28
  301. classiq/interface/generator/state_preparation/distributions.py +0 -53
  302. classiq/interface/generator/state_preparation/exponential_state_preparation.py +0 -14
  303. classiq/interface/generator/state_preparation/ghz_state_preparation.py +0 -14
  304. classiq/interface/generator/state_preparation/metrics.py +0 -41
  305. classiq/interface/generator/state_preparation/state_preparation.py +0 -113
  306. classiq/interface/generator/state_preparation/state_preparation_abc.py +0 -24
  307. classiq/interface/generator/state_preparation/uniform_distibution_state_preparation.py +0 -13
  308. classiq/interface/generator/state_preparation/w_state_preparation.py +0 -13
  309. classiq/interface/generator/ucc.py +0 -74
  310. classiq/interface/helpers/backward_compatibility.py +0 -9
  311. classiq/model_expansions/transformers/type_modifier_inference.py +0 -392
  312. classiq/open_library/functions/lookup_table.py +0 -58
  313. classiq/qmod/builtins/functions/chemistry.py +0 -123
  314. classiq/qmod/builtins/functions/qsvm.py +0 -24
  315. {classiq-0.93.0.dist-info → classiq-0.99.0.dist-info}/licenses/LICENSE.txt +0 -0
@@ -1,7 +1,7 @@
1
1
  from collections.abc import Iterator, Sequence
2
2
  from contextlib import contextmanager
3
3
  from dataclasses import dataclass, field
4
- from typing import Generic, Optional, TypeVar
4
+ from typing import Generic, TypeVar
5
5
 
6
6
  from classiq.interface.exceptions import (
7
7
  ClassiqExpansionError,
@@ -13,6 +13,7 @@ from classiq.interface.generator.compiler_keywords import (
13
13
  )
14
14
  from classiq.interface.generator.functions.builtins.internal_operators import (
15
15
  BLOCK_OPERATOR_NAME,
16
+ SKIP_CONTROL_OPERATOR_NAME,
16
17
  WITHIN_APPLY_NAME,
17
18
  )
18
19
  from classiq.interface.model.model import MAIN_FUNCTION_NAME
@@ -39,7 +40,11 @@ from classiq.model_expansions.utils.counted_name_allocator import CountedNameAll
39
40
 
40
41
  ClosureType = TypeVar("ClosureType", bound=Closure)
41
42
 
42
- BLOCKS_ALLOWED_CAPTURING = (WITHIN_APPLY_NAME, BLOCK_OPERATOR_NAME)
43
+ BLOCKS_ALLOWED_CAPTURING = (
44
+ WITHIN_APPLY_NAME,
45
+ BLOCK_OPERATOR_NAME,
46
+ SKIP_CONTROL_OPERATOR_NAME,
47
+ )
43
48
 
44
49
 
45
50
  @dataclass
@@ -87,6 +92,10 @@ class FunctionContext(OperationContext[FunctionClosure]):
87
92
  def is_lambda(self) -> bool:
88
93
  return self.closure.is_lambda
89
94
 
95
+ @property
96
+ def permutation(self) -> bool:
97
+ return self.closure.permutation
98
+
90
99
 
91
100
  class OperationBuilder:
92
101
  def __init__(
@@ -95,7 +104,7 @@ class OperationBuilder:
95
104
  self._operations: list[OperationContext] = []
96
105
  self._blocks: list[str] = []
97
106
  self._functions_scope = functions_scope
98
- self._current_source_ref: Optional[SourceReference] = None
107
+ self._current_source_ref: SourceReference | None = None
99
108
  self._counted_name_allocator = counted_name_allocator
100
109
 
101
110
  @property
@@ -201,9 +210,7 @@ class OperationBuilder:
201
210
  parent_block.captured_vars.update(captured_vars)
202
211
 
203
212
  @contextmanager
204
- def source_ref_context(
205
- self, source_ref: Optional[SourceReference]
206
- ) -> Iterator[None]:
213
+ def source_ref_context(self, source_ref: SourceReference | None) -> Iterator[None]:
207
214
  previous_source_ref = self._current_source_ref
208
215
  self._current_source_ref = source_ref
209
216
  yield
@@ -218,6 +225,7 @@ class OperationBuilder:
218
225
  name=name,
219
226
  body=function_context.body,
220
227
  positional_arg_declarations=params,
228
+ permutation=function_context.permutation,
221
229
  )
222
230
 
223
231
  def _get_expanded_function_name(self, function_context: FunctionContext) -> str:
@@ -113,10 +113,7 @@ def translate_ast_arg_to_python_qmod(param: PositionalArg, value: Any) -> Any:
113
113
  if isinstance(param, PortDeclaration):
114
114
  return _create_qvar_for_qtype(value.quantum_type, value.handle)
115
115
  if isinstance(param, QuantumOperandDeclaration):
116
- if not param.is_list or not param.is_generative:
117
- return QTerminalCallable(param)
118
- inner_decl = param.model_copy(update={"is_list": False})
119
- return [QTerminalCallable(inner_decl, index_=idx) for idx in range(len(value))]
116
+ return QTerminalCallable(param)
120
117
  if (
121
118
  isinstance(value, QmodStructInstance)
122
119
  and not param.classical_type.is_purely_generative
@@ -175,20 +172,18 @@ class _InterpreterExpandable(QFunc):
175
172
  scope_func_decls: dict[str, QuantumFunctionDeclaration] = {}
176
173
  for name, evaluated in self._interpreter._builder.current_scope.items():
177
174
  value = evaluated.value
175
+ if (
176
+ isinstance(value, list)
177
+ and len(value) > 0
178
+ and isinstance(value[0], FunctionClosure)
179
+ ):
180
+ value = value[0]
178
181
  if isinstance(value, FunctionClosure):
179
182
  scope_func_decls[name] = QuantumFunctionDeclaration(
180
183
  name=name,
181
184
  positional_arg_declarations=value.positional_arg_declarations,
182
185
  )
183
186
  continue
184
- op_param = self._interpreter._builder.current_function.parameters_dict.get(
185
- name
186
- )
187
- if isinstance(op_param, QuantumOperandDeclaration):
188
- scope_func_decls[name] = QuantumFunctionDeclaration(
189
- name=name,
190
- positional_arg_declarations=op_param.positional_arg_declarations,
191
- )
192
187
  return (
193
188
  nameables_to_dict(self._interpreter._get_function_declarations())
194
189
  | scope_func_decls
@@ -1,10 +1,10 @@
1
1
  import ast
2
2
  from abc import abstractmethod
3
3
  from collections import defaultdict
4
- from collections.abc import Sequence
4
+ from collections.abc import Callable, Sequence
5
5
  from contextlib import nullcontext
6
6
  from functools import singledispatchmethod
7
- from typing import Any, Callable, cast
7
+ from typing import Any, cast
8
8
 
9
9
  from pydantic import ValidationError
10
10
 
@@ -42,9 +42,6 @@ from classiq.interface.model.quantum_statement import QuantumStatement
42
42
 
43
43
  from classiq.evaluators.classical_expression import process_scope_val
44
44
  from classiq.evaluators.qmod_annotated_expression import QmodAnnotatedExpression
45
- from classiq.evaluators.qmod_expression_visitors.qmod_expression_bwc import (
46
- QmodExpressionBwc,
47
- )
48
45
  from classiq.evaluators.qmod_expression_visitors.qmod_expression_evaluator import (
49
46
  evaluate_qmod_expression,
50
47
  )
@@ -214,7 +211,6 @@ class BaseInterpreter:
214
211
  if expression.is_evaluated():
215
212
  return Evaluated(value=expression.value.value)
216
213
  expr_ast = ast.parse(expression.expr, mode="eval").body
217
- expr_ast = QmodExpressionBwc().visit(expr_ast)
218
214
  expr_val = self._eval_expr(ast.unparse(expr_ast), treat_qnum_as_float)
219
215
  if simplify and not expr_val.has_value(expr_val.root):
220
216
  simplified_expr = simplify_qmod_expression(expr_val)
@@ -328,7 +324,7 @@ class BaseInterpreter:
328
324
  def emit_statement(self, statement: QuantumStatement) -> None:
329
325
  source_ref = statement.source_ref
330
326
  error_context = (
331
- self._error_manager.node_context(statement)
327
+ self._error_manager.source_ref_context(statement.source_ref)
332
328
  if source_ref is not None
333
329
  else nullcontext()
334
330
  )
@@ -41,7 +41,8 @@ class FrontendGenerativeInterpreter(GenerativeInterpreter):
41
41
  if module is None or not module.__name__.startswith("classiq."):
42
42
  file_name = os.path.split(frame.filename)[-1]
43
43
  if (
44
- frame.positions is not None
44
+ hasattr(frame, "positions")
45
+ and frame.positions is not None
45
46
  and frame.positions.lineno is not None
46
47
  and frame.positions.col_offset is not None
47
48
  and frame.positions.end_lineno is not None
@@ -1,5 +1,5 @@
1
1
  from functools import singledispatchmethod
2
- from typing import Any, Optional
2
+ from typing import Any
3
3
 
4
4
  import numpy as np
5
5
  from numpy.random import permutation
@@ -119,9 +119,9 @@ class GenerativeInterpreter(BaseInterpreter):
119
119
  def infer_symbolic_parameters(
120
120
  self,
121
121
  functions: list[NativeFunctionDefinition],
122
- additional_signatures: Optional[
122
+ additional_signatures: None | (
123
123
  list[NamedParamsQuantumFunctionDeclaration]
124
- ] = None,
124
+ ) = None,
125
125
  ) -> None:
126
126
  pass
127
127
 
@@ -134,6 +134,7 @@ class GenerativeInterpreter(BaseInterpreter):
134
134
  function.func_decl.name or "<lambda>"
135
135
  ),
136
136
  positional_arg_declarations=function.named_func_decl.positional_arg_declarations,
137
+ permutation=function.named_func_decl.permutation,
137
138
  )
138
139
 
139
140
  closure_class: type[FunctionClosure]
@@ -152,6 +153,7 @@ class GenerativeInterpreter(BaseInterpreter):
152
153
  closure = closure_class.create(
153
154
  name=func_decl.name,
154
155
  positional_arg_declarations=func_decl.positional_arg_declarations,
156
+ permutation=func_decl.permutation,
155
157
  body=function.body,
156
158
  scope=Scope(parent=self._builder.current_scope),
157
159
  lambda_external_vars=self._builder.current_block.captured_vars,
@@ -1,4 +1,4 @@
1
- from typing import TYPE_CHECKING, Any, Union
1
+ from typing import TYPE_CHECKING, Any
2
2
 
3
3
  import sympy
4
4
 
@@ -193,7 +193,7 @@ class AllocateEmitter(Emitter[Allocate]):
193
193
 
194
194
  def _interpret_size(
195
195
  self, size: Expression, var_name: str
196
- ) -> Union[int, float, sympy.Basic, QmodAnnotatedExpression]:
196
+ ) -> int | float | sympy.Basic | QmodAnnotatedExpression:
197
197
  size_value = self._interpreter.evaluate(size).value
198
198
  if not (
199
199
  (
@@ -221,7 +221,7 @@ class AllocateEmitter(Emitter[Allocate]):
221
221
 
222
222
  def _interpret_is_signed(
223
223
  self, is_signed: Expression
224
- ) -> Union[bool, sympy.Basic, QmodAnnotatedExpression]:
224
+ ) -> bool | sympy.Basic | QmodAnnotatedExpression:
225
225
  is_signed_value = self._interpreter.evaluate(is_signed).value
226
226
  if not self._allow_symbolic_attrs and not (
227
227
  isinstance(is_signed_value, bool)
@@ -238,7 +238,7 @@ class AllocateEmitter(Emitter[Allocate]):
238
238
 
239
239
  def _interpret_fraction_digits(
240
240
  self, fraction_digits: Expression
241
- ) -> Union[int, float, sympy.Expr, QmodAnnotatedExpression]:
241
+ ) -> int | float | sympy.Expr | QmodAnnotatedExpression:
242
242
  fraction_digits_value = self._interpreter.evaluate(fraction_digits).value
243
243
  if not self._allow_symbolic_attrs and not (
244
244
  isinstance(fraction_digits_value, (int, float))
@@ -1,4 +1,4 @@
1
- from typing import TYPE_CHECKING, Optional
1
+ from typing import TYPE_CHECKING
2
2
 
3
3
  from classiq.interface.exceptions import ClassiqExpansionError
4
4
  from classiq.interface.generator.expressions.expression import Expression
@@ -111,9 +111,7 @@ class AssignmentResultProcessor(Emitter[QuantumAssignmentOperation]):
111
111
  self._assign_to_inferred_var_and_bind(op, result_type, expression_type)
112
112
  return True
113
113
 
114
- def _infer_expression_type(
115
- self, op: ArithmeticOperation
116
- ) -> Optional[QuantumScalar]:
114
+ def _infer_expression_type(self, op: ArithmeticOperation) -> QuantumScalar | None:
117
115
  expr = self._evaluate_expression(op.expression)
118
116
  expr_val = expr.value.value
119
117
  if isinstance(expr_val, QmodAnnotatedExpression):
@@ -2,7 +2,6 @@ from collections.abc import Sequence
2
2
  from itertools import chain, combinations
3
3
  from typing import (
4
4
  Generic,
5
- Optional,
6
5
  cast,
7
6
  )
8
7
  from uuid import UUID
@@ -16,9 +15,7 @@ from classiq.interface.exceptions import ClassiqExpansionError
16
15
  from classiq.interface.generator.functions.port_declaration import (
17
16
  PortDeclarationDirection,
18
17
  )
19
- from classiq.interface.generator.functions.type_modifier import TypeModifier
20
18
  from classiq.interface.generator.types.compilation_metadata import CompilationMetadata
21
- from classiq.interface.helpers.backward_compatibility import zip_strict
22
19
  from classiq.interface.helpers.text_utils import are, readable_list, s
23
20
  from classiq.interface.model.block import Block
24
21
  from classiq.interface.model.classical_parameter_declaration import (
@@ -72,8 +69,8 @@ from classiq.model_expansions.scope import (
72
69
  Scope,
73
70
  )
74
71
  from classiq.model_expansions.transformers.model_renamer import ModelRenamer
75
- from classiq.model_expansions.transformers.type_modifier_inference import (
76
- TypeModifierValidation,
72
+ from classiq.model_expansions.visitors.uncomputation_signature_inference import (
73
+ infer_and_validate_uncomputation_signature,
77
74
  )
78
75
  from classiq.qmod.pretty_print.expression_to_python import transform_expression
79
76
  from classiq.qmod.semantics.validation.signature_validation import (
@@ -106,7 +103,7 @@ def _validate_cloning(evaluated_args: list[Evaluated]) -> None:
106
103
  def _validate_gen_args(
107
104
  function: FunctionClosure, evaluated_args: list[Evaluated]
108
105
  ) -> None:
109
- for param, arg in zip_strict(
106
+ for param, arg in zip(
110
107
  function.positional_arg_declarations, evaluated_args, strict=True
111
108
  ):
112
109
  if (
@@ -158,7 +155,7 @@ class CallEmitter(Generic[QuantumStatementT], Emitter[QuantumStatementT], ModelR
158
155
  self,
159
156
  name: str,
160
157
  body: Sequence[QuantumStatement],
161
- debug_info: Optional[FunctionDebugInfo] = None,
158
+ debug_info: FunctionDebugInfo | None = None,
162
159
  ) -> QuantumFunctionCall:
163
160
  wrapping_function = FunctionClosure.create(
164
161
  name=self._counted_name_allocator.allocate(name),
@@ -172,7 +169,7 @@ class CallEmitter(Generic[QuantumStatementT], Emitter[QuantumStatementT], ModelR
172
169
  self,
173
170
  function: FunctionClosure,
174
171
  args: list[ArgValue],
175
- propagated_debug_info: Optional[FunctionDebugInfo],
172
+ propagated_debug_info: FunctionDebugInfo | None,
176
173
  ) -> QuantumFunctionCall:
177
174
  call = self._create_quantum_function_call(
178
175
  function, args, propagated_debug_info=propagated_debug_info
@@ -182,8 +179,8 @@ class CallEmitter(Generic[QuantumStatementT], Emitter[QuantumStatementT], ModelR
182
179
 
183
180
  @staticmethod
184
181
  def _get_back_ref(
185
- propagated_debug_info: Optional[FunctionDebugInfo],
186
- ) -> Optional[UUID]:
182
+ propagated_debug_info: FunctionDebugInfo | None,
183
+ ) -> UUID | None:
187
184
  if propagated_debug_info is None:
188
185
  return None
189
186
  if propagated_debug_info.node is None:
@@ -194,7 +191,7 @@ class CallEmitter(Generic[QuantumStatementT], Emitter[QuantumStatementT], ModelR
194
191
  self,
195
192
  function: FunctionClosure,
196
193
  args: list[ArgValue],
197
- propagated_debug_info: Optional[FunctionDebugInfo],
194
+ propagated_debug_info: FunctionDebugInfo | None,
198
195
  ) -> QuantumFunctionCall:
199
196
  function = function.clone()
200
197
  function = function.set_depth(self._builder.current_function.depth + 1)
@@ -218,7 +215,7 @@ class CallEmitter(Generic[QuantumStatementT], Emitter[QuantumStatementT], ModelR
218
215
  new_positional_arg_decls = new_declaration.positional_arg_declarations
219
216
  evaluated_args = [
220
217
  arg
221
- for param, arg in zip_strict(
218
+ for param, arg in zip(
222
219
  function.positional_arg_declarations, evaluated_args, strict=True
223
220
  )
224
221
  if isinstance(arg.value, QuantumVariable)
@@ -235,7 +232,7 @@ class CallEmitter(Generic[QuantumStatementT], Emitter[QuantumStatementT], ModelR
235
232
  )
236
233
  new_positional_args = [
237
234
  arg.emit(param)
238
- for param, arg in zip_strict(
235
+ for param, arg in zip(
239
236
  new_positional_arg_decls[
240
237
  : len(new_positional_arg_decls) - len(captured_args)
241
238
  ],
@@ -394,6 +391,7 @@ class CallEmitter(Generic[QuantumStatementT], Emitter[QuantumStatementT], ModelR
394
391
  function,
395
392
  evaluated_args,
396
393
  ),
394
+ permutation=function.permutation,
397
395
  )
398
396
 
399
397
  def _validate_call_args(
@@ -425,27 +423,30 @@ class CallEmitter(Generic[QuantumStatementT], Emitter[QuantumStatementT], ModelR
425
423
  def _validate_type_modifiers(
426
424
  self, func_context: FunctionContext, func_def: NativeFunctionDefinition
427
425
  ) -> None:
428
- if self._should_override_type_modifiers(func_context):
429
- self._override_type_modifiers(func_def)
430
-
431
- unchecked = self._functions_compilation_metadata.get(
426
+ compilation_metadata = self._functions_compilation_metadata.get(
432
427
  func_context.name, CompilationMetadata()
433
- ).unchecked
434
- TypeModifierValidation(
435
- skip_validation=self._interpreter.skip_type_modifier_validation
436
- ).run(func_def, unchecked)
428
+ )
429
+ infer_and_validate_uncomputation_signature(
430
+ func_def,
431
+ disable_perm_check=self._interpreter.skip_type_modifier_validation
432
+ or compilation_metadata.disable_perm_check,
433
+ disable_const_checks=self._interpreter.skip_type_modifier_validation
434
+ or compilation_metadata.disable_const_checks,
435
+ tighten_signature=self._should_tighten_signature(func_context),
436
+ )
437
437
 
438
438
  @staticmethod
439
- def _should_override_type_modifiers(func_context: FunctionContext) -> bool:
439
+ def _should_tighten_signature(func_context: FunctionContext) -> bool:
440
440
  """
441
- The type modifier can be changed according to the operand passed to the
442
- function. For example,
443
- apply_to_all(X, q) --> q will be Permutable after expansion
444
- apply_to_all(H, q) --> q will be Quantum after expansion
445
- This also holds for the intermediate lambda created during the expansion.
446
-
447
- We don't override the type modifier if it's explicitly specified (Permutable or
448
- Const), neither in the function declaration nor in the operand declaration.
441
+ In some cases we want to tighten the function signature (adding "const" or
442
+ "permutation" modifiers) when possible:
443
+ - Lambda functions (which are defined without modifiers)
444
+ - Functions which receive operands and their modifiers depend on the operand
445
+
446
+ For example:
447
+ - apply_to_all(Z, q) --> q will become `const` and the function will become `permutation`
448
+ - apply_to_all(X, q) --> the function will become `permutation`
449
+ - apply_to_all(H, q) --> no change
449
450
  """
450
451
 
451
452
  if func_context.is_lambda:
@@ -466,10 +467,3 @@ class CallEmitter(Generic[QuantumStatementT], Emitter[QuantumStatementT], ModelR
466
467
  for param_decl in orig_func.positional_arg_declarations
467
468
  )
468
469
  )
469
-
470
- @staticmethod
471
- def _override_type_modifiers(func_def: NativeFunctionDefinition) -> None:
472
- # only override the modifier if it's unspecified (not Permutable or Const)
473
- for port in func_def.port_declarations:
474
- if port.type_modifier is TypeModifier.Mutable:
475
- port.type_modifier = TypeModifier.Inferred
@@ -1,5 +1,5 @@
1
1
  from itertools import chain
2
- from typing import TYPE_CHECKING, Generic, Optional
2
+ from typing import TYPE_CHECKING, Generic
3
3
 
4
4
  from classiq.interface.generator.functions.port_declaration import (
5
5
  PortDeclarationDirection,
@@ -41,7 +41,7 @@ class DeclarativeCallEmitter(
41
41
  return True
42
42
 
43
43
  def _is_function_purely_declarative(
44
- self, function: FunctionClosure, seen_funcs: Optional[set[str]] = None
44
+ self, function: FunctionClosure, seen_funcs: set[str] | None = None
45
45
  ) -> bool:
46
46
  if seen_funcs is None:
47
47
  seen_funcs = set()
@@ -3,9 +3,7 @@ from collections.abc import Sequence
3
3
  from typing import (
4
4
  TYPE_CHECKING,
5
5
  Generic,
6
- Optional,
7
6
  TypeVar,
8
- Union,
9
7
  )
10
8
 
11
9
  from classiq.interface.debug_info.debug_info import (
@@ -113,9 +111,9 @@ class Emitter(Generic[QuantumStatementT], ABC):
113
111
  self,
114
112
  op: QuantumOperation,
115
113
  context_name: str,
116
- block_names: Union[None, str, list[str]] = None,
117
- params: Optional[Sequence[PositionalArg]] = None,
118
- scope: Optional[Scope] = None,
114
+ block_names: None | str | list[str] = None,
115
+ params: Sequence[PositionalArg] | None = None,
116
+ scope: Scope | None = None,
119
117
  ) -> OperationContext:
120
118
  if isinstance(block_names, str):
121
119
  block_names = [block_names]
@@ -1,4 +1,4 @@
1
- from typing import TYPE_CHECKING, Optional
1
+ from typing import TYPE_CHECKING
2
2
 
3
3
  from classiq.interface.exceptions import (
4
4
  ClassiqExpansionError,
@@ -24,7 +24,7 @@ class ExpressionEvaluator(Emitter[QuantumOperation]):
24
24
  interpreter: "BaseInterpreter",
25
25
  expression_name: str,
26
26
  *,
27
- readable_expression_name: Optional[str] = None,
27
+ readable_expression_name: str | None = None,
28
28
  simplify: bool = False,
29
29
  treat_qnum_as_float: bool = False,
30
30
  allow_link_time_vars: bool = True,
@@ -73,7 +73,7 @@ class ExpressionEvaluator(Emitter[QuantumOperation]):
73
73
  link_time_vars.append(var_name)
74
74
  self._capture_classical_var(var_name, var_type)
75
75
  if not self._allow_link_time_vars and len(link_time_vars) > 0:
76
- link_time_message = f"link-time variable{s(link_time_vars)} {readable_list(link_time_vars, quote=True)}"
76
+ link_time_message = f"execution parameter{s(link_time_vars)} {readable_list(link_time_vars, quote=True)}"
77
77
  else:
78
78
  link_time_message = None
79
79
  if not self._allow_runtime_vars and len(runtime_vars) > 0:
@@ -1,5 +1,4 @@
1
1
  from classiq.interface.exceptions import ClassiqExpansionError
2
- from classiq.interface.helpers.backward_compatibility import zip_strict
3
2
  from classiq.interface.model.skip_control import SkipControl
4
3
 
5
4
  from classiq.model_expansions.function_builder import FunctionContext
@@ -9,7 +8,7 @@ from classiq.model_expansions.quantum_operations.emitter import Emitter
9
8
  class SkipControlVerifier(Emitter[SkipControl]):
10
9
  def emit(self, skip_control: SkipControl, /) -> bool:
11
10
  for op, block in list(
12
- zip_strict(self._builder._operations, self._builder._blocks, strict=True)
11
+ zip(self._builder._operations, self._builder._blocks, strict=True)
13
12
  )[::-1]:
14
13
  if isinstance(op, FunctionContext):
15
14
  break
@@ -1,4 +1,4 @@
1
- from typing import TYPE_CHECKING, Union, cast
1
+ from typing import TYPE_CHECKING, cast
2
2
 
3
3
  from classiq.interface.exceptions import ClassiqExpansionError
4
4
  from classiq.interface.generator.functions.classical_type import ClassicalType
@@ -38,7 +38,7 @@ class VariableDeclarationStatementEmitter(Emitter[VariableDeclarationStatement])
38
38
  raise ClassiqExpansionError(
39
39
  f"Variable {variable_declaration.name!r} is already defined"
40
40
  )
41
- var_value: Union[QuantumSymbol, ClassicalSymbol]
41
+ var_value: QuantumSymbol | ClassicalSymbol
42
42
  if variable_declaration.is_quantum:
43
43
  var_value = self._get_quantum_var(var_decl)
44
44
  else:
@@ -68,7 +68,7 @@ class QuantumSymbol(QuantumVariable):
68
68
  return self.handle
69
69
 
70
70
  def __getitem__(
71
- self, item: Union[slice, int, QmodAnnotatedExpression]
71
+ self, item: slice | int | QmodAnnotatedExpression
72
72
  ) -> "QuantumSymbol":
73
73
  if isinstance(item, slice):
74
74
  return self._slice(item.start, item.stop)
@@ -76,8 +76,8 @@ class QuantumSymbol(QuantumVariable):
76
76
 
77
77
  def _slice(
78
78
  self,
79
- start: Union[int, QmodAnnotatedExpression],
80
- end: Union[int, QmodAnnotatedExpression],
79
+ start: int | QmodAnnotatedExpression,
80
+ end: int | QmodAnnotatedExpression,
81
81
  ) -> "QuantumSymbol":
82
82
  if not isinstance(self.quantum_type, QuantumBitvector):
83
83
  raise ClassiqExpansionError(
@@ -119,7 +119,7 @@ class QuantumSymbol(QuantumVariable):
119
119
  ),
120
120
  )
121
121
 
122
- def _subscript(self, index: Union[int, QmodAnnotatedExpression]) -> "QuantumSymbol":
122
+ def _subscript(self, index: int | QmodAnnotatedExpression) -> "QuantumSymbol":
123
123
  if not isinstance(self.quantum_type, QuantumBitvector):
124
124
  raise ClassiqExpansionError(
125
125
  f"{self.quantum_type.type_name} is not subscriptable"
@@ -188,7 +188,7 @@ class QuantumSymbolList(QuantumVariable):
188
188
  )
189
189
  if len(handles) == 0:
190
190
  raise ClassiqExpansionError("Empty concatenation expression")
191
- length: Optional[Expression]
191
+ length: Expression | None
192
192
  if any(not symbol.quantum_type.has_size_in_bits for symbol in symbols):
193
193
  length = None
194
194
  else:
@@ -252,7 +252,7 @@ class Evaluated: # FIXME: Merge with EvaluatedExpression if possible
252
252
 
253
253
  return value
254
254
 
255
- def emit(self, param: Optional[AnonPositionalArg] = None) -> ArgValue:
255
+ def emit(self, param: AnonPositionalArg | None = None) -> ArgValue:
256
256
  from classiq.model_expansions.closure import FunctionClosure
257
257
 
258
258
  if isinstance(self.value, (QuantumVariable, FunctionClosure)):
@@ -278,7 +278,7 @@ else:
278
278
  class Scope(EvaluatedUserDict):
279
279
  def __init__(
280
280
  self,
281
- data: Optional[dict[str, Evaluated]] = None,
281
+ data: dict[str, Evaluated] | None = None,
282
282
  /,
283
283
  *,
284
284
  parent: Optional["Scope"] = None,
@@ -44,6 +44,7 @@ def add_functions_to_scope(
44
44
  value=FunctionClosure.create(
45
45
  name=function.name,
46
46
  positional_arg_declarations=function.positional_arg_declarations,
47
+ permutation=function.permutation,
47
48
  body=function.body,
48
49
  scope=Scope(parent=scope),
49
50
  )
@@ -64,6 +65,7 @@ def add_generative_functions_to_scope(
64
65
  value=GenerativeFunctionClosure.create(
65
66
  name=name,
66
67
  positional_arg_declarations=function.func_decl.positional_arg_declarations,
68
+ permutation=function.permutation,
67
69
  scope=Scope(parent=scope),
68
70
  generative_blocks={"body": function},
69
71
  )
@@ -76,6 +78,7 @@ def _init_builtins_scope(scope: Scope) -> None:
76
78
  value=FunctionClosure.create(
77
79
  name=builtin_function.name,
78
80
  positional_arg_declarations=builtin_function.positional_arg_declarations,
81
+ permutation=builtin_function.permutation,
79
82
  scope=Scope(parent=scope),
80
83
  is_atomic=True,
81
84
  )
@@ -85,6 +88,7 @@ def _init_builtins_scope(scope: Scope) -> None:
85
88
  value=FunctionClosure.create(
86
89
  name=builtin_function.name,
87
90
  positional_arg_declarations=builtin_function.positional_arg_declarations,
91
+ permutation=builtin_function.permutation,
88
92
  scope=Scope(parent=scope),
89
93
  )
90
94
  )
@@ -2,7 +2,7 @@ import ast
2
2
  from collections.abc import Iterator, Mapping, Sequence
3
3
  from contextlib import contextmanager
4
4
  from itertools import chain, zip_longest
5
- from typing import Optional, cast
5
+ from typing import cast
6
6
 
7
7
  from classiq.interface.generator.expressions.atomic_expression_functions import (
8
8
  CLASSICAL_ATTRIBUTES,
@@ -19,7 +19,7 @@ from classiq.interface.model.classical_parameter_declaration import (
19
19
  AnonClassicalParameterDeclaration,
20
20
  )
21
21
  from classiq.interface.model.handle_binding import FieldHandleBinding, HandleBinding
22
- from classiq.interface.model.model_visitor import ModelVisitor
22
+ from classiq.interface.model.model_visitor import ModelStatementsVisitor
23
23
  from classiq.interface.model.native_function_definition import NativeFunctionDefinition
24
24
  from classiq.interface.model.quantum_function_call import ArgValue, QuantumFunctionCall
25
25
  from classiq.interface.model.quantum_function_declaration import (
@@ -84,13 +84,13 @@ def _get_param_expressions(param: AnonPositionalArg) -> list[Expression]:
84
84
  return param.quantum_type.expressions
85
85
 
86
86
 
87
- class SymbolicParamInference(ModelVisitor):
87
+ class SymbolicParamInference(ModelStatementsVisitor):
88
88
  def __init__(
89
89
  self,
90
90
  functions: list[NativeFunctionDefinition],
91
- additional_signatures: Optional[
91
+ additional_signatures: None | (
92
92
  list[NamedParamsQuantumFunctionDeclaration]
93
- ] = None,
93
+ ) = None,
94
94
  ) -> None:
95
95
  self._functions = nameables_to_dict(functions)
96
96
  self._additional_signatures = (
@@ -166,7 +166,7 @@ class SymbolicParamInference(ModelVisitor):
166
166
  else:
167
167
  for expr in _get_expressions(arg):
168
168
  self._process_nested_compile_time_expression(expr.expr)
169
- self.generic_visit(call)
169
+ self.visit(call.positional_args)
170
170
 
171
171
  def _get_params(self, call: QuantumFunctionCall) -> Sequence[AnonPositionalArg]:
172
172
  name = call.func_name