classiq 0.92.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 (318) 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 +239 -11
  52. classiq/applications/qsvm/qsvm_data_generation.py +1 -2
  53. classiq/evaluators/classical_expression.py +0 -4
  54. classiq/evaluators/parameter_types.py +20 -12
  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 +10 -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 +8 -4
  207. classiq/model_expansions/quantum_operations/allocate.py +4 -4
  208. classiq/model_expansions/quantum_operations/assignment_result_processor.py +8 -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 +61 -29
  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 +19 -14
  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 +173 -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/classical_variable.py +4 -2
  244. classiq/qmod/cparam.py +2 -8
  245. classiq/qmod/create_model_function.py +7 -7
  246. classiq/qmod/declaration_inferrer.py +33 -30
  247. classiq/qmod/expression_query.py +7 -4
  248. classiq/qmod/model_state_container.py +2 -2
  249. classiq/qmod/native/pretty_printer.py +25 -14
  250. classiq/qmod/pretty_print/expression_to_python.py +5 -3
  251. classiq/qmod/pretty_print/pretty_printer.py +39 -17
  252. classiq/qmod/python_classical_type.py +40 -13
  253. classiq/qmod/qfunc.py +124 -19
  254. classiq/qmod/qmod_constant.py +2 -2
  255. classiq/qmod/qmod_parameter.py +5 -2
  256. classiq/qmod/qmod_variable.py +47 -46
  257. classiq/qmod/quantum_callable.py +18 -13
  258. classiq/qmod/quantum_expandable.py +33 -26
  259. classiq/qmod/quantum_function.py +84 -36
  260. classiq/qmod/semantics/annotation/call_annotation.py +5 -5
  261. classiq/qmod/semantics/error_manager.py +12 -14
  262. classiq/qmod/semantics/lambdas.py +1 -2
  263. classiq/qmod/semantics/validation/types_validation.py +1 -2
  264. classiq/qmod/symbolic.py +2 -4
  265. classiq/qmod/symbolic_expr.py +12 -4
  266. classiq/qmod/utilities.py +13 -20
  267. classiq/qmod/write_qmod.py +3 -4
  268. classiq/quantum_program.py +1 -3
  269. classiq/synthesis.py +11 -7
  270. {classiq-0.92.0.dist-info → classiq-0.99.0.dist-info}/METADATA +38 -37
  271. {classiq-0.92.0.dist-info → classiq-0.99.0.dist-info}/RECORD +273 -300
  272. classiq-0.99.0.dist-info/WHEEL +4 -0
  273. classiq-0.99.0.dist-info/licenses/LICENSE.txt +27 -0
  274. classiq/applications/chemistry/ansatz_parameters.py +0 -29
  275. classiq/applications/chemistry/chemistry_execution_parameters.py +0 -16
  276. classiq/applications/chemistry/chemistry_model_constructor.py +0 -532
  277. classiq/applications/chemistry/ground_state_problem.py +0 -42
  278. classiq/applications/qsvm/__init__.py +0 -8
  279. classiq/applications/qsvm/qsvm.py +0 -11
  280. classiq/evaluators/qmod_expression_visitors/qmod_expression_bwc.py +0 -129
  281. classiq/execution/iqcc.py +0 -128
  282. classiq/interface/applications/qsvm.py +0 -117
  283. classiq/interface/chemistry/elements.py +0 -120
  284. classiq/interface/chemistry/fermionic_operator.py +0 -208
  285. classiq/interface/chemistry/ground_state_problem.py +0 -132
  286. classiq/interface/chemistry/ground_state_result.py +0 -8
  287. classiq/interface/chemistry/molecule.py +0 -71
  288. classiq/interface/execution/iqcc.py +0 -44
  289. classiq/interface/generator/application_apis/chemistry_declarations.py +0 -69
  290. classiq/interface/generator/application_apis/entangler_declarations.py +0 -29
  291. classiq/interface/generator/application_apis/qsvm_declarations.py +0 -6
  292. classiq/interface/generator/chemistry_function_params.py +0 -50
  293. classiq/interface/generator/entangler_params.py +0 -72
  294. classiq/interface/generator/entanglers.py +0 -14
  295. classiq/interface/generator/hamiltonian_evolution/qdrift.py +0 -27
  296. classiq/interface/generator/hartree_fock.py +0 -26
  297. classiq/interface/generator/hva.py +0 -22
  298. classiq/interface/generator/linear_pauli_rotations.py +0 -92
  299. classiq/interface/generator/qft.py +0 -37
  300. classiq/interface/generator/qsvm.py +0 -96
  301. classiq/interface/generator/state_preparation/__init__.py +0 -14
  302. classiq/interface/generator/state_preparation/bell_state_preparation.py +0 -27
  303. classiq/interface/generator/state_preparation/computational_basis_state_preparation.py +0 -28
  304. classiq/interface/generator/state_preparation/distributions.py +0 -53
  305. classiq/interface/generator/state_preparation/exponential_state_preparation.py +0 -14
  306. classiq/interface/generator/state_preparation/ghz_state_preparation.py +0 -14
  307. classiq/interface/generator/state_preparation/metrics.py +0 -41
  308. classiq/interface/generator/state_preparation/state_preparation.py +0 -113
  309. classiq/interface/generator/state_preparation/state_preparation_abc.py +0 -24
  310. classiq/interface/generator/state_preparation/uniform_distibution_state_preparation.py +0 -13
  311. classiq/interface/generator/state_preparation/w_state_preparation.py +0 -13
  312. classiq/interface/generator/ucc.py +0 -74
  313. classiq/interface/helpers/backward_compatibility.py +0 -9
  314. classiq/model_expansions/transformers/type_modifier_inference.py +0 -392
  315. classiq/open_library/functions/lookup_table.py +0 -58
  316. classiq/qmod/builtins/functions/chemistry.py +0 -123
  317. classiq/qmod/builtins/functions/qsvm.py +0 -24
  318. classiq-0.92.0.dist-info/WHEEL +0 -4
@@ -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,
@@ -245,7 +247,9 @@ class GenerativeInterpreter(BaseInterpreter):
245
247
  def emit_variable_declaration(
246
248
  self, variable_declaration: VariableDeclarationStatement
247
249
  ) -> None:
248
- VariableDeclarationStatementEmitter(self).emit(variable_declaration)
250
+ VariableDeclarationStatementEmitter(
251
+ self, allow_symbolic_vars=self._symbolic_parameters_switch
252
+ ).emit(variable_declaration)
249
253
 
250
254
  @emit.register
251
255
  def emit_classical_if(self, classical_if: ClassicalIf) -> None:
@@ -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
@@ -62,6 +62,12 @@ class AssignmentResultProcessor(Emitter[QuantumAssignmentOperation]):
62
62
  if isinstance(result_symbol, ClassicalSymbol):
63
63
  return False
64
64
  result_type = result_symbol.quantum_type
65
+ if not isinstance(result_type, QuantumScalar):
66
+ raise ClassiqExpansionError(
67
+ f"Cannot assign into a non-scalar quantum variable "
68
+ f"{str(result_symbol.handle)!r} of type "
69
+ f"{result_type.raw_qmod_type_name}"
70
+ )
65
71
 
66
72
  if not (
67
73
  isinstance(op, ArithmeticOperation)
@@ -105,9 +111,7 @@ class AssignmentResultProcessor(Emitter[QuantumAssignmentOperation]):
105
111
  self._assign_to_inferred_var_and_bind(op, result_type, expression_type)
106
112
  return True
107
113
 
108
- def _infer_expression_type(
109
- self, op: ArithmeticOperation
110
- ) -> Optional[QuantumScalar]:
114
+ def _infer_expression_type(self, op: ArithmeticOperation) -> QuantumScalar | None:
111
115
  expr = self._evaluate_expression(op.expression)
112
116
  expr_val = expr.value.value
113
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,8 +1,9 @@
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
5
5
  from classiq.interface.generator.functions.concrete_types import ConcreteType
6
+ from classiq.interface.helpers.text_utils import readable_list, s
6
7
  from classiq.interface.model.handle_binding import HandleBinding
7
8
  from classiq.interface.model.quantum_type import QuantumType
8
9
  from classiq.interface.model.variable_declaration_statement import (
@@ -13,11 +14,21 @@ from classiq.evaluators.parameter_types import (
13
14
  evaluate_type_in_classical_symbol,
14
15
  evaluate_type_in_quantum_symbol,
15
16
  )
17
+ from classiq.evaluators.qmod_annotated_expression import QmodAnnotatedExpression
16
18
  from classiq.model_expansions.quantum_operations.emitter import Emitter
17
19
  from classiq.model_expansions.scope import ClassicalSymbol, Evaluated, QuantumSymbol
18
20
 
21
+ if TYPE_CHECKING:
22
+ from classiq.model_expansions.interpreters.base_interpreter import BaseInterpreter
23
+
19
24
 
20
25
  class VariableDeclarationStatementEmitter(Emitter[VariableDeclarationStatement]):
26
+ def __init__(
27
+ self, interpreter: "BaseInterpreter", allow_symbolic_vars: bool = False
28
+ ) -> None:
29
+ super().__init__(interpreter)
30
+ self._allow_symbolic_vars = allow_symbolic_vars
31
+
21
32
  def emit(self, variable_declaration: VariableDeclarationStatement, /) -> bool:
22
33
  var_decl = variable_declaration.model_copy(
23
34
  update=dict(back_ref=variable_declaration.uuid)
@@ -27,38 +38,59 @@ class VariableDeclarationStatementEmitter(Emitter[VariableDeclarationStatement])
27
38
  raise ClassiqExpansionError(
28
39
  f"Variable {variable_declaration.name!r} is already defined"
29
40
  )
30
- var_value: Union[QuantumSymbol, ClassicalSymbol]
41
+ var_value: QuantumSymbol | ClassicalSymbol
31
42
  if variable_declaration.is_quantum:
32
- if TYPE_CHECKING:
33
- assert isinstance(var_decl.qmod_type, QuantumType)
34
- updated_quantum_type = evaluate_type_in_quantum_symbol(
35
- var_decl.qmod_type,
36
- self._current_scope,
37
- var_decl.name,
38
- )
39
- var_decl.qmod_type = updated_quantum_type
40
- var_value = QuantumSymbol(
41
- handle=HandleBinding(name=var_decl.name),
42
- quantum_type=updated_quantum_type,
43
- )
44
- self._builder.current_block.captured_vars.init_var(
45
- var_decl.name, self._builder.current_function
46
- )
43
+ var_value = self._get_quantum_var(var_decl)
47
44
  else:
48
- if TYPE_CHECKING:
49
- assert isinstance(var_decl.qmod_type, ClassicalType)
50
- updated_classical_type = evaluate_type_in_classical_symbol(
51
- var_decl.qmod_type,
52
- self._current_scope,
53
- var_decl.name,
54
- )
55
- var_decl.qmod_type = cast(ConcreteType, updated_classical_type)
56
- var_value = ClassicalSymbol(
57
- handle=HandleBinding(name=var_decl.name),
58
- classical_type=updated_classical_type,
59
- )
45
+ var_value = self._get_classical_var(var_decl)
60
46
  self._current_scope[variable_declaration.name] = Evaluated(
61
47
  value=var_value, defining_function=self._builder.current_function
62
48
  )
63
49
  self.emit_statement(var_decl)
64
50
  return True
51
+
52
+ def _get_quantum_var(self, var_decl: VariableDeclarationStatement) -> QuantumSymbol:
53
+ updated_quantum_type = evaluate_type_in_quantum_symbol(
54
+ cast(QuantumType, var_decl.qmod_type),
55
+ self._current_scope,
56
+ var_decl.name,
57
+ )
58
+ if not self._allow_symbolic_vars:
59
+ symbolic_variables = list(
60
+ dict.fromkeys(
61
+ classical_var.name
62
+ for expr in updated_quantum_type.expressions
63
+ if isinstance(expr_val := expr.value.value, QmodAnnotatedExpression)
64
+ for classical_var in expr_val.get_classical_vars().values()
65
+ )
66
+ )
67
+ if len(symbolic_variables) > 0:
68
+ raise ClassiqExpansionError(
69
+ f"Variable type is instantiated with non-compile-time "
70
+ f"variable{s(symbolic_variables)} "
71
+ f"{readable_list(symbolic_variables, quote=True)}"
72
+ )
73
+ var_decl.qmod_type = updated_quantum_type
74
+ var_value = QuantumSymbol(
75
+ handle=HandleBinding(name=var_decl.name),
76
+ quantum_type=updated_quantum_type,
77
+ )
78
+ self._builder.current_block.captured_vars.init_var(
79
+ var_decl.name, self._builder.current_function
80
+ )
81
+ return var_value
82
+
83
+ def _get_classical_var(
84
+ self, var_decl: VariableDeclarationStatement
85
+ ) -> ClassicalSymbol:
86
+ updated_classical_type = evaluate_type_in_classical_symbol(
87
+ cast(ClassicalType, var_decl.qmod_type),
88
+ self._current_scope,
89
+ var_decl.name,
90
+ )
91
+ var_decl.qmod_type = cast(ConcreteType, updated_classical_type)
92
+ var_value = ClassicalSymbol(
93
+ handle=HandleBinding(name=var_decl.name),
94
+ classical_type=updated_classical_type,
95
+ )
96
+ return var_value