classiq 0.52.0__py3-none-any.whl → 0.54.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 (303) hide show
  1. classiq/__init__.py +1 -3
  2. classiq/_analyzer_extras/_ipywidgets_async_extension.py +2 -1
  3. classiq/_internals/__init__.py +0 -20
  4. classiq/_internals/api_wrapper.py +23 -17
  5. classiq/_internals/async_utils.py +1 -3
  6. classiq/_internals/authentication/auth0.py +5 -5
  7. classiq/_internals/authentication/device.py +5 -4
  8. classiq/_internals/authentication/password_manager.py +3 -3
  9. classiq/_internals/authentication/token_manager.py +3 -2
  10. classiq/_internals/client.py +11 -13
  11. classiq/_internals/config.py +2 -2
  12. classiq/_internals/jobs.py +7 -6
  13. classiq/_internals/type_validation.py +9 -9
  14. classiq/analyzer/__init__.py +1 -3
  15. classiq/analyzer/analyzer.py +8 -7
  16. classiq/analyzer/analyzer_utilities.py +8 -8
  17. classiq/analyzer/rb.py +11 -11
  18. classiq/applications/__init__.py +1 -3
  19. classiq/applications/chemistry/__init__.py +1 -3
  20. classiq/applications/chemistry/ansatz_parameters.py +4 -4
  21. classiq/applications/chemistry/chemistry_model_constructor.py +10 -9
  22. classiq/applications/combinatorial_helpers/combinatorial_problem_utils.py +26 -9
  23. classiq/applications/combinatorial_helpers/encoding_mapping.py +10 -10
  24. classiq/applications/combinatorial_helpers/encoding_utils.py +4 -4
  25. classiq/applications/combinatorial_helpers/memory.py +5 -7
  26. classiq/applications/combinatorial_helpers/optimization_model.py +43 -24
  27. classiq/applications/combinatorial_helpers/pauli_helpers/pauli_utils.py +4 -6
  28. classiq/applications/combinatorial_helpers/pyomo_utils.py +95 -24
  29. classiq/applications/combinatorial_helpers/sympy_utils.py +2 -2
  30. classiq/applications/combinatorial_helpers/transformations/encoding.py +8 -8
  31. classiq/applications/combinatorial_helpers/transformations/fixed_variables.py +5 -5
  32. classiq/applications/combinatorial_helpers/transformations/ising_converter.py +7 -9
  33. classiq/applications/combinatorial_helpers/transformations/penalty.py +1 -2
  34. classiq/applications/combinatorial_helpers/transformations/sign_seperation.py +1 -2
  35. classiq/applications/combinatorial_helpers/transformations/slack_variables.py +1 -2
  36. classiq/applications/combinatorial_optimization/__init__.py +1 -3
  37. classiq/applications/combinatorial_optimization/combinatorial_optimization_config.py +2 -2
  38. classiq/applications/combinatorial_optimization/examples/__init__.py +1 -3
  39. classiq/applications/finance/__init__.py +1 -3
  40. classiq/applications/grover/__init__.py +1 -3
  41. classiq/applications/grover/grover_model_constructor.py +7 -9
  42. classiq/applications/hamiltonian/pauli_decomposition.py +6 -6
  43. classiq/applications/qnn/__init__.py +1 -3
  44. classiq/applications/qnn/circuit_utils.py +5 -5
  45. classiq/applications/qnn/datasets/__init__.py +1 -3
  46. classiq/applications/qnn/datasets/dataset_base_classes.py +5 -4
  47. classiq/applications/qnn/datasets/dataset_parity.py +2 -2
  48. classiq/applications/qnn/gradients/simple_quantum_gradient.py +2 -1
  49. classiq/applications/qnn/qlayer.py +25 -6
  50. classiq/applications/qnn/torch_utils.py +2 -2
  51. classiq/applications/qnn/types.py +5 -5
  52. classiq/applications/qsvm/qsvm.py +1 -3
  53. classiq/applications/qsvm/qsvm_data_generation.py +3 -3
  54. classiq/applications/qsvm/qsvm_model_constructor.py +5 -5
  55. classiq/execution/__init__.py +3 -3
  56. classiq/execution/all_hardware_devices.py +1 -3
  57. classiq/execution/execution_session.py +57 -16
  58. classiq/execution/iqcc.py +1 -1
  59. classiq/execution/jobs.py +4 -4
  60. classiq/execution/qaoa.py +84 -0
  61. classiq/execution/qnn.py +3 -3
  62. classiq/executor.py +4 -4
  63. classiq/interface/_version.py +1 -1
  64. classiq/interface/analyzer/analysis_params.py +9 -10
  65. classiq/interface/analyzer/cytoscape_graph.py +5 -5
  66. classiq/interface/analyzer/result.py +17 -17
  67. classiq/interface/applications/qsvm.py +6 -10
  68. classiq/interface/backend/backend_preferences.py +4 -3
  69. classiq/interface/backend/ionq/ionq_quantum_program.py +4 -5
  70. classiq/interface/backend/pydantic_backend.py +1 -2
  71. classiq/interface/chemistry/fermionic_operator.py +5 -5
  72. classiq/interface/chemistry/ground_state_problem.py +7 -8
  73. classiq/interface/chemistry/molecule.py +4 -4
  74. classiq/interface/chemistry/operator.py +11 -13
  75. classiq/interface/combinatorial_optimization/examples/ascending_sequence.py +1 -3
  76. classiq/interface/combinatorial_optimization/examples/integer_portfolio_optimization.py +2 -4
  77. classiq/interface/combinatorial_optimization/examples/knapsack.py +3 -3
  78. classiq/interface/combinatorial_optimization/examples/mht.py +2 -3
  79. classiq/interface/combinatorial_optimization/examples/portfolio_variations.py +2 -2
  80. classiq/interface/combinatorial_optimization/examples/set_cover.py +1 -2
  81. classiq/interface/combinatorial_optimization/mht_qaoa_input.py +5 -7
  82. classiq/interface/combinatorial_optimization/optimization_problem.py +2 -2
  83. classiq/interface/combinatorial_optimization/result.py +1 -3
  84. classiq/interface/debug_info/debug_info.py +8 -7
  85. classiq/interface/exceptions.py +11 -7
  86. classiq/interface/execution/iqcc.py +1 -3
  87. classiq/interface/execution/jobs.py +2 -2
  88. classiq/interface/execution/primitives.py +3 -3
  89. classiq/interface/executor/aws_execution_cost.py +4 -4
  90. classiq/interface/executor/execution_request.py +2 -3
  91. classiq/interface/executor/execution_result.py +3 -3
  92. classiq/interface/executor/iqae_result.py +3 -5
  93. classiq/interface/executor/optimizer_preferences.py +2 -2
  94. classiq/interface/executor/quantum_code.py +6 -6
  95. classiq/interface/executor/register_initialization.py +2 -4
  96. classiq/interface/executor/result.py +35 -28
  97. classiq/interface/executor/vqe_result.py +8 -8
  98. classiq/interface/finance/function_input.py +2 -2
  99. classiq/interface/finance/gaussian_model_input.py +5 -5
  100. classiq/interface/finance/log_normal_model_input.py +2 -2
  101. classiq/interface/finance/model_input.py +1 -2
  102. classiq/interface/generator/adjacency.py +1 -3
  103. classiq/interface/generator/ansatz_library.py +4 -4
  104. classiq/interface/generator/application_apis/finance_declarations.py +1 -1
  105. classiq/interface/generator/arith/argument_utils.py +3 -3
  106. classiq/interface/generator/arith/arithmetic.py +7 -7
  107. classiq/interface/generator/arith/arithmetic_arg_type_validator.py +5 -5
  108. classiq/interface/generator/arith/arithmetic_expression_abc.py +11 -11
  109. classiq/interface/generator/arith/arithmetic_expression_parser.py +8 -7
  110. classiq/interface/generator/arith/arithmetic_expression_validator.py +8 -8
  111. classiq/interface/generator/arith/arithmetic_operations.py +4 -3
  112. classiq/interface/generator/arith/arithmetic_param_getters.py +6 -6
  113. classiq/interface/generator/arith/arithmetic_result_builder.py +9 -9
  114. classiq/interface/generator/arith/ast_node_rewrite.py +2 -1
  115. classiq/interface/generator/arith/binary_ops.py +10 -13
  116. classiq/interface/generator/arith/extremum_operations.py +3 -2
  117. classiq/interface/generator/arith/logical_ops.py +7 -6
  118. classiq/interface/generator/arith/number_utils.py +4 -4
  119. classiq/interface/generator/arith/register_user_input.py +4 -4
  120. classiq/interface/generator/arith/unary_ops.py +2 -1
  121. classiq/interface/generator/builtin_api_builder.py +2 -1
  122. classiq/interface/generator/circuit_code/circuit_code.py +4 -4
  123. classiq/interface/generator/circuit_code/types_and_constants.py +3 -5
  124. classiq/interface/generator/complex_type.py +1 -2
  125. classiq/interface/generator/control_state.py +2 -2
  126. classiq/interface/generator/custom_ansatz.py +1 -3
  127. classiq/interface/generator/distance.py +3 -5
  128. classiq/interface/generator/excitations.py +3 -2
  129. classiq/interface/generator/expressions/enums/finance_functions.py +1 -3
  130. classiq/interface/generator/expressions/evaluated_expression.py +4 -3
  131. classiq/interface/generator/expressions/expression.py +4 -5
  132. classiq/interface/generator/expressions/expression_constants.py +4 -4
  133. classiq/interface/generator/expressions/qmod_qarray_proxy.py +2 -1
  134. classiq/interface/generator/expressions/qmod_qscalar_proxy.py +2 -1
  135. classiq/interface/generator/expressions/qmod_qstruct_proxy.py +2 -1
  136. classiq/interface/generator/expressions/qmod_sized_proxy.py +2 -1
  137. classiq/interface/generator/expressions/qmod_struct_instance.py +2 -1
  138. classiq/interface/generator/expressions/sympy_supported_expressions.py +11 -13
  139. classiq/interface/generator/finance.py +2 -2
  140. classiq/interface/generator/function_param_library.py +6 -6
  141. classiq/interface/generator/function_params.py +13 -19
  142. classiq/interface/generator/functions/classical_function_declaration.py +4 -3
  143. classiq/interface/generator/functions/classical_type.py +13 -13
  144. classiq/interface/generator/functions/concrete_types.py +1 -2
  145. classiq/interface/generator/functions/function_declaration.py +1 -1
  146. classiq/interface/generator/functions/qmod_python_interface.py +2 -1
  147. classiq/interface/generator/functions/type_name.py +3 -2
  148. classiq/interface/generator/generated_circuit_data.py +34 -22
  149. classiq/interface/generator/grover_diffuser.py +7 -7
  150. classiq/interface/generator/grover_operator.py +2 -2
  151. classiq/interface/generator/hardware/hardware_data.py +7 -6
  152. classiq/interface/generator/hardware_efficient_ansatz.py +8 -8
  153. classiq/interface/generator/identity.py +5 -6
  154. classiq/interface/generator/linear_pauli_rotations.py +6 -6
  155. classiq/interface/generator/mcu.py +2 -2
  156. classiq/interface/generator/mcx.py +6 -6
  157. classiq/interface/generator/model/__init__.py +1 -3
  158. classiq/interface/generator/model/constraints.py +2 -2
  159. classiq/interface/generator/model/model.py +5 -6
  160. classiq/interface/generator/model/preferences/preferences.py +7 -6
  161. classiq/interface/generator/model/quantum_register.py +6 -11
  162. classiq/interface/generator/oracles/arithmetic_oracle.py +1 -2
  163. classiq/interface/generator/oracles/custom_oracle.py +2 -2
  164. classiq/interface/generator/oracles/oracle_abc.py +6 -5
  165. classiq/interface/generator/partitioned_register.py +6 -5
  166. classiq/interface/generator/piecewise_linear_amplitude_loading.py +8 -7
  167. classiq/interface/generator/qpe.py +4 -4
  168. classiq/interface/generator/qsvm.py +3 -3
  169. classiq/interface/generator/quantum_function_call.py +24 -29
  170. classiq/interface/generator/quantum_program.py +9 -9
  171. classiq/interface/generator/register_role.py +2 -4
  172. classiq/interface/generator/slice_parsing_utils.py +4 -3
  173. classiq/interface/generator/standard_gates/standard_gates.py +3 -3
  174. classiq/interface/generator/state_preparation/bell_state_preparation.py +3 -3
  175. classiq/interface/generator/state_preparation/distributions.py +6 -5
  176. classiq/interface/generator/state_preparation/metrics.py +2 -4
  177. classiq/interface/generator/state_preparation/state_preparation.py +4 -4
  178. classiq/interface/generator/synthesis_metadata/synthesis_execution_data.py +3 -3
  179. classiq/interface/generator/transpiler_basis_gates.py +2 -2
  180. classiq/interface/generator/types/enum_declaration.py +2 -3
  181. classiq/interface/generator/types/qstruct_declaration.py +2 -1
  182. classiq/interface/generator/types/struct_declaration.py +3 -2
  183. classiq/interface/generator/ucc.py +2 -1
  184. classiq/interface/generator/unitary_gate.py +2 -2
  185. classiq/interface/generator/user_defined_function_params.py +1 -1
  186. classiq/interface/generator/validations/flow_graph.py +6 -5
  187. classiq/interface/generator/validations/validator_functions.py +3 -2
  188. classiq/interface/generator/visitor.py +9 -14
  189. classiq/interface/hardware.py +5 -6
  190. classiq/interface/helpers/custom_encoders.py +2 -2
  191. classiq/interface/helpers/custom_pydantic_types.py +8 -9
  192. classiq/interface/helpers/dotdict.py +18 -0
  193. classiq/interface/helpers/hashable_mixin.py +3 -2
  194. classiq/interface/helpers/hashable_pydantic_base_model.py +2 -1
  195. classiq/interface/helpers/pydantic_model_helpers.py +4 -3
  196. classiq/interface/helpers/validation_helpers.py +2 -2
  197. classiq/interface/ide/ide_data.py +11 -15
  198. classiq/interface/ide/visual_model.py +33 -22
  199. classiq/interface/jobs.py +2 -2
  200. classiq/interface/model/bind_operation.py +5 -4
  201. classiq/interface/model/classical_parameter_declaration.py +2 -2
  202. classiq/interface/model/handle_binding.py +3 -2
  203. classiq/interface/model/inplace_binary_operation.py +2 -1
  204. classiq/interface/model/model.py +12 -11
  205. classiq/interface/model/native_function_definition.py +10 -0
  206. classiq/interface/model/port_declaration.py +2 -2
  207. classiq/interface/model/quantum_expressions/amplitude_loading_operation.py +3 -2
  208. classiq/interface/model/quantum_expressions/arithmetic_operation.py +3 -2
  209. classiq/interface/model/quantum_expressions/quantum_expression.py +8 -7
  210. classiq/interface/model/quantum_function_call.py +9 -14
  211. classiq/interface/model/quantum_function_declaration.py +10 -12
  212. classiq/interface/model/quantum_lambda_function.py +3 -16
  213. classiq/interface/model/quantum_statement.py +4 -3
  214. classiq/interface/model/quantum_type.py +5 -5
  215. classiq/interface/model/statement_block.py +2 -3
  216. classiq/interface/model/validation_handle.py +5 -4
  217. classiq/interface/server/global_versions.py +3 -3
  218. classiq/model_expansions/atomic_expression_functions_defs.py +3 -2
  219. classiq/model_expansions/call_to_model_converter.py +190 -0
  220. classiq/model_expansions/capturing/captured_var_manager.py +4 -6
  221. classiq/model_expansions/capturing/propagated_var_stack.py +7 -7
  222. classiq/model_expansions/closure.py +17 -9
  223. classiq/model_expansions/evaluators/arg_type_match.py +3 -2
  224. classiq/model_expansions/evaluators/argument_types.py +3 -3
  225. classiq/model_expansions/evaluators/control.py +3 -3
  226. classiq/model_expansions/evaluators/parameter_types.py +7 -7
  227. classiq/model_expansions/evaluators/quantum_type_utils.py +2 -1
  228. classiq/model_expansions/evaluators/type_type_match.py +1 -1
  229. classiq/model_expansions/expression_evaluator.py +10 -9
  230. classiq/model_expansions/expression_renamer.py +6 -6
  231. classiq/model_expansions/function_builder.py +19 -12
  232. classiq/model_expansions/generative_functions.py +3 -2
  233. classiq/model_expansions/interpreter.py +31 -19
  234. classiq/model_expansions/model_tables.py +14 -14
  235. classiq/model_expansions/quantum_operations/bind.py +2 -4
  236. classiq/model_expansions/quantum_operations/classicalif.py +1 -1
  237. classiq/model_expansions/quantum_operations/control.py +2 -4
  238. classiq/model_expansions/quantum_operations/emitter.py +10 -13
  239. classiq/model_expansions/quantum_operations/expression_operation.py +23 -16
  240. classiq/model_expansions/quantum_operations/inplace_binary_operation.py +164 -38
  241. classiq/model_expansions/quantum_operations/phase.py +6 -6
  242. classiq/model_expansions/quantum_operations/quantum_assignment_operation.py +25 -5
  243. classiq/model_expansions/quantum_operations/quantum_function_call.py +41 -2
  244. classiq/model_expansions/quantum_operations/repeat.py +1 -3
  245. classiq/model_expansions/scope.py +11 -10
  246. classiq/model_expansions/scope_initialization.py +6 -5
  247. classiq/model_expansions/sympy_conversion/expression_to_sympy.py +6 -6
  248. classiq/model_expansions/sympy_conversion/sympy_to_python.py +2 -2
  249. classiq/model_expansions/visitors/variable_references.py +5 -4
  250. classiq/qmod/__init__.py +2 -0
  251. classiq/qmod/builtins/classical_execution_primitives.py +9 -9
  252. classiq/qmod/builtins/functions/__init__.py +75 -53
  253. classiq/qmod/builtins/functions/amplitude_estimation.py +4 -1
  254. classiq/qmod/builtins/functions/arithmetic.py +14 -1
  255. classiq/qmod/builtins/functions/discrete_sine_cosine_transform.py +86 -6
  256. classiq/qmod/builtins/functions/grover.py +41 -45
  257. classiq/qmod/builtins/functions/hea.py +60 -4
  258. classiq/qmod/builtins/functions/linear_pauli_rotation.py +26 -4
  259. classiq/qmod/builtins/functions/modular_exponentiation.py +90 -29
  260. classiq/qmod/builtins/functions/operators.py +1 -1
  261. classiq/qmod/builtins/functions/qaoa_penalty.py +14 -5
  262. classiq/qmod/builtins/functions/qft_functions.py +57 -0
  263. classiq/qmod/builtins/functions/qpe.py +20 -4
  264. classiq/qmod/builtins/functions/qsvt.py +49 -4
  265. classiq/qmod/builtins/functions/standard_gates.py +18 -18
  266. classiq/qmod/builtins/functions/state_preparation.py +92 -10
  267. classiq/qmod/builtins/functions/swap_test.py +7 -1
  268. classiq/qmod/builtins/functions/utility_functions.py +43 -0
  269. classiq/qmod/builtins/functions/variational.py +53 -0
  270. classiq/qmod/builtins/operations.py +4 -5
  271. classiq/qmod/cfunc.py +2 -2
  272. classiq/qmod/classical_function.py +3 -7
  273. classiq/qmod/create_model_function.py +19 -8
  274. classiq/qmod/declaration_inferrer.py +7 -10
  275. classiq/qmod/expression_query.py +3 -3
  276. classiq/qmod/generative.py +2 -1
  277. classiq/qmod/model_state_container.py +5 -7
  278. classiq/qmod/native/__init__.py +1 -3
  279. classiq/qmod/native/expression_to_qmod.py +9 -8
  280. classiq/qmod/native/pretty_printer.py +6 -5
  281. classiq/qmod/pretty_print/__init__.py +1 -3
  282. classiq/qmod/pretty_print/expression_to_python.py +13 -12
  283. classiq/qmod/pretty_print/pretty_printer.py +13 -12
  284. classiq/qmod/python_classical_type.py +8 -4
  285. classiq/qmod/qfunc.py +4 -4
  286. classiq/qmod/qmod_parameter.py +3 -1
  287. classiq/qmod/qmod_variable.py +11 -10
  288. classiq/qmod/quantum_expandable.py +32 -15
  289. classiq/qmod/quantum_function.py +34 -5
  290. classiq/qmod/semantics/annotation.py +1 -1
  291. classiq/qmod/semantics/error_manager.py +8 -7
  292. classiq/qmod/semantics/static_semantics_visitor.py +19 -24
  293. classiq/qmod/semantics/validation/constants_validation.py +1 -1
  294. classiq/qmod/semantics/validation/func_call_validation.py +2 -2
  295. classiq/qmod/semantics/validation/main_validation.py +33 -0
  296. classiq/qmod/semantics/validation/types_validation.py +2 -1
  297. classiq/qmod/symbolic.py +5 -8
  298. classiq/qmod/symbolic_type.py +2 -2
  299. classiq/qmod/synthesize_separately.py +16 -0
  300. {classiq-0.52.0.dist-info → classiq-0.54.0.dist-info}/METADATA +1 -1
  301. {classiq-0.52.0.dist-info → classiq-0.54.0.dist-info}/RECORD +302 -295
  302. classiq/qmod/builtins/functions/qft.py +0 -23
  303. {classiq-0.52.0.dist-info → classiq-0.54.0.dist-info}/WHEEL +0 -0
@@ -1,5 +1,3 @@
1
- from typing import List
2
-
3
1
  from classiq.interface.exceptions import ClassiqExpansionError
4
2
  from classiq.interface.model.bind_operation import BindOperation
5
3
 
@@ -18,11 +16,11 @@ class BindEmitter(Emitter[BindOperation]):
18
16
  def emit(self, bind: BindOperation, /) -> None:
19
17
  with self._propagated_var_stack.capture_variables(bind):
20
18
  pass
21
- inputs: List[QuantumSymbol] = [
19
+ inputs: list[QuantumSymbol] = [
22
20
  self._interpreter.evaluate(arg).as_type(QuantumSymbol)
23
21
  for arg in bind.in_handles
24
22
  ]
25
- outputs: List[QuantumSymbol] = [
23
+ outputs: list[QuantumSymbol] = [
26
24
  self._interpreter.evaluate(arg).as_type(QuantumSymbol)
27
25
  for arg in bind.out_handles
28
26
  ]
@@ -1,4 +1,4 @@
1
- from typing import Sequence
1
+ from collections.abc import Sequence
2
2
 
3
3
  from classiq.interface.model.classical_if import ClassicalIf
4
4
  from classiq.interface.model.quantum_function_call import QuantumFunctionCall
@@ -1,5 +1,3 @@
1
- from typing import List, Tuple
2
-
3
1
  from sympy import Equality
4
2
  from sympy.logic.boolalg import Boolean
5
3
  from typing_extensions import TypeGuard
@@ -160,7 +158,7 @@ class ControlEmitter(ExpressionOperationEmitter[Control]):
160
158
  def _emit_with_x_gates(
161
159
  self, control: Control, ctrl: QmodSizedProxy, ctrl_state: str
162
160
  ) -> None:
163
- compute_op: List[ConcreteQuantumStatement] = []
161
+ compute_op: list[ConcreteQuantumStatement] = []
164
162
 
165
163
  x_gate_value = self._get_x_gate_value(ctrl_state)
166
164
  if x_gate_value != 0:
@@ -194,7 +192,7 @@ class ControlEmitter(ExpressionOperationEmitter[Control]):
194
192
 
195
193
  def _get_array_cast_ops(
196
194
  self, ctrl: QmodQNumProxy
197
- ) -> Tuple[VariableDeclarationStatement, BindOperation]:
195
+ ) -> tuple[VariableDeclarationStatement, BindOperation]:
198
196
  array_cast = self._counted_name_allocator.allocate(
199
197
  f"{ctrl.handle}{ARRAY_CAST_SUFFIX}"
200
198
  )
@@ -1,11 +1,9 @@
1
1
  from abc import abstractmethod
2
+ from collections.abc import Sequence
2
3
  from typing import (
3
4
  TYPE_CHECKING,
4
- Dict,
5
5
  Generic,
6
- List,
7
6
  Optional,
8
- Sequence,
9
7
  TypeVar,
10
8
  Union,
11
9
  cast,
@@ -18,7 +16,7 @@ from classiq.interface.generator.expressions.evaluated_expression import (
18
16
  EvaluatedExpression,
19
17
  )
20
18
  from classiq.interface.generator.expressions.expression import Expression
21
- from classiq.interface.ide.visual_model import OperationLevel
19
+ from classiq.interface.generator.generated_circuit_data import OperationLevel
22
20
  from classiq.interface.model.classical_parameter_declaration import (
23
21
  ClassicalParameterDeclaration,
24
22
  )
@@ -63,7 +61,6 @@ from classiq.qmod.quantum_function import GenerativeQFunc
63
61
  if TYPE_CHECKING:
64
62
  from classiq.model_expansions.interpreter import Interpreter
65
63
 
66
-
67
64
  QuantumStatementT = TypeVar("QuantumStatementT", bound=QuantumStatement)
68
65
 
69
66
 
@@ -74,7 +71,7 @@ class Emitter(Generic[QuantumStatementT]):
74
71
  self._scope_guard = self._interpreter._scope_guard
75
72
  self._machine_precision = self._interpreter._model.preferences.machine_precision
76
73
 
77
- self._generative_contexts: Dict[str, OperationContext] = {}
74
+ self._generative_contexts: dict[str, OperationContext] = {}
78
75
 
79
76
  @abstractmethod
80
77
  def emit(self, statement: QuantumStatementT, /) -> None:
@@ -103,7 +100,7 @@ class Emitter(Generic[QuantumStatementT]):
103
100
  return self._interpreter._current_scope
104
101
 
105
102
  @property
106
- def _expanded_functions(self) -> List[NativeFunctionDefinition]:
103
+ def _expanded_functions(self) -> list[NativeFunctionDefinition]:
107
104
  return self._interpreter._expanded_functions
108
105
 
109
106
  @property
@@ -125,14 +122,14 @@ class Emitter(Generic[QuantumStatementT]):
125
122
  return self._create_quantum_function_call(wrapping_function, list())
126
123
 
127
124
  def _emit_quantum_function_call(
128
- self, function: FunctionClosure, args: List[ArgValue]
125
+ self, function: FunctionClosure, args: list[ArgValue]
129
126
  ) -> QuantumFunctionCall:
130
127
  call = self._create_quantum_function_call(function, args)
131
128
  self._builder.emit_statement(call)
132
129
  return call
133
130
 
134
131
  def _create_quantum_function_call(
135
- self, function: FunctionClosure, args: List[ArgValue]
132
+ self, function: FunctionClosure, args: list[ArgValue]
136
133
  ) -> QuantumFunctionCall:
137
134
  evaluated_args = [self._interpreter.evaluate(arg) for arg in args]
138
135
  new_declaration = self._prepare_fully_typed_declaration(
@@ -206,10 +203,10 @@ class Emitter(Generic[QuantumStatementT]):
206
203
 
207
204
  def _get_new_positional_args(
208
205
  self,
209
- evaluated_args: List[Evaluated],
206
+ evaluated_args: list[Evaluated],
210
207
  is_atomic: bool,
211
208
  new_positional_arg_decls: Sequence[PositionalArg],
212
- ) -> List[ArgValue]:
209
+ ) -> list[ArgValue]:
213
210
  evaluated_args = add_information_from_output_arguments(
214
211
  new_positional_arg_decls, evaluated_args
215
212
  )
@@ -230,7 +227,7 @@ class Emitter(Generic[QuantumStatementT]):
230
227
  return positional_args
231
228
 
232
229
  def _prepare_fully_typed_declaration(
233
- self, function: FunctionClosure, evaluated_args: List[Evaluated]
230
+ self, function: FunctionClosure, evaluated_args: list[Evaluated]
234
231
  ) -> NamedParamsQuantumFunctionDeclaration:
235
232
  """
236
233
  Given, for example,
@@ -260,7 +257,7 @@ class Emitter(Generic[QuantumStatementT]):
260
257
  self,
261
258
  op: QuantumOperation,
262
259
  context_name: str,
263
- block_names: Union[None, str, List[str]] = None,
260
+ block_names: Union[None, str, list[str]] = None,
264
261
  func_decl: Optional[NamedParamsQuantumFunctionDeclaration] = None,
265
262
  ) -> OperationContext:
266
263
  if isinstance(block_names, str):
@@ -1,7 +1,7 @@
1
1
  import ast
2
2
  from abc import abstractmethod
3
3
  from itertools import chain
4
- from typing import TYPE_CHECKING, Dict, List, Tuple, TypeVar
4
+ from typing import TYPE_CHECKING, TypeVar
5
5
 
6
6
  from classiq.interface.exceptions import (
7
7
  ClassiqExpansionError,
@@ -26,6 +26,7 @@ from classiq.interface.model.quantum_type import (
26
26
  QuantumBit,
27
27
  QuantumBitvector,
28
28
  QuantumNumeric,
29
+ QuantumType,
29
30
  )
30
31
  from classiq.interface.model.variable_declaration_statement import (
31
32
  VariableDeclarationStatement,
@@ -48,7 +49,7 @@ class ExpressionOperationEmitter(Emitter[ExpressionOperationT]):
48
49
  self,
49
50
  op: ExpressionOperationT,
50
51
  expression: Expression,
51
- symbols_to_split: List[QuantumSymbol],
52
+ symbols_to_split: list[QuantumSymbol],
52
53
  ) -> None:
53
54
  symbols_parts, bind_ops = self._get_bind_ops(symbols_to_split)
54
55
 
@@ -62,14 +63,13 @@ class ExpressionOperationEmitter(Emitter[ExpressionOperationT]):
62
63
  )
63
64
  )
64
65
 
65
- new_expression = self._update_op_expression(
66
- {
67
- symbol.handle: symbol_part_var_name
68
- for symbol, symbol_part_var_name in chain.from_iterable(symbols_parts)
69
- },
70
- expression,
71
- )
66
+ symbol_mapping = {
67
+ symbol.handle: (symbol_part_var_name, symbol.quantum_type)
68
+ for symbol, symbol_part_var_name in chain.from_iterable(symbols_parts)
69
+ }
70
+ new_expression = self._update_op_expression(symbol_mapping, expression)
72
71
  new_op = op.model_copy(update=dict(expression=new_expression))
72
+ new_op = self._get_updated_op_split_symbols(new_op, symbol_mapping)
73
73
 
74
74
  self._interpreter.emit_statement(
75
75
  WithinApply(
@@ -79,9 +79,16 @@ class ExpressionOperationEmitter(Emitter[ExpressionOperationT]):
79
79
  )
80
80
  )
81
81
 
82
+ @staticmethod
83
+ def _get_updated_op_split_symbols(
84
+ op: ExpressionOperationT,
85
+ symbol_mapping: dict[HandleBinding, tuple[str, QuantumType]],
86
+ ) -> ExpressionOperationT:
87
+ return op
88
+
82
89
  def _update_op_expression(
83
90
  self,
84
- symbol_parts: Dict[HandleBinding, str],
91
+ symbol_mapping: dict[HandleBinding, tuple[str, QuantumType]],
85
92
  expression: Expression,
86
93
  ) -> Expression:
87
94
  vrc = VarRefCollector(ignore_duplicated_handles=True)
@@ -90,9 +97,9 @@ class ExpressionOperationEmitter(Emitter[ExpressionOperationT]):
90
97
  new_expr_str = expression.expr
91
98
  for handle in vrc.var_handles:
92
99
  collapsed_handle = handle.collapse()
93
- if collapsed_handle in symbol_parts:
100
+ if collapsed_handle in symbol_mapping:
94
101
  new_expr_str = new_expr_str.replace(
95
- str(handle), symbol_parts[collapsed_handle]
102
+ str(handle), symbol_mapping[collapsed_handle][0]
96
103
  )
97
104
  self._check_all_handles_were_replaced(new_expr_str)
98
105
 
@@ -115,8 +122,8 @@ class ExpressionOperationEmitter(Emitter[ExpressionOperationT]):
115
122
 
116
123
  def _get_bind_ops(
117
124
  self,
118
- symbols_to_split: List[QuantumSymbol],
119
- ) -> Tuple[List[List[Tuple[QuantumSymbol, str]]], List[BindOperation]]:
125
+ symbols_to_split: list[QuantumSymbol],
126
+ ) -> tuple[list[list[tuple[QuantumSymbol, str]]], list[BindOperation]]:
120
127
  bind_ops = []
121
128
  symbols_parts = []
122
129
  for symbol in symbols_to_split:
@@ -135,7 +142,7 @@ class ExpressionOperationEmitter(Emitter[ExpressionOperationT]):
135
142
 
136
143
  def _get_symbol_parts(
137
144
  self, symbol: QuantumSymbol
138
- ) -> List[Tuple[QuantumSymbol, str]]:
145
+ ) -> list[tuple[QuantumSymbol, str]]:
139
146
  quantum_type = symbol.quantum_type
140
147
 
141
148
  if isinstance(quantum_type, (QuantumBit, QuantumNumeric)):
@@ -169,7 +176,7 @@ class ExpressionOperationEmitter(Emitter[ExpressionOperationT]):
169
176
  )
170
177
  )
171
178
 
172
- def _get_symbols_to_split(self, expression: Expression) -> List[QuantumSymbol]:
179
+ def _get_symbols_to_split(self, expression: Expression) -> list[QuantumSymbol]:
173
180
  vrc = VarRefCollector(ignore_duplicated_handles=True)
174
181
  vrc.visit(ast.parse(expression.expr))
175
182
  symbol_names_to_split = dict.fromkeys(
@@ -1,10 +1,12 @@
1
- from typing import TYPE_CHECKING, List, Tuple, Union
1
+ from typing import TYPE_CHECKING, Optional, Union
2
2
 
3
+ from classiq.interface.exceptions import ClassiqInternalExpansionError
3
4
  from classiq.interface.generator.expressions.expression import Expression
4
5
  from classiq.interface.generator.functions.port_declaration import (
5
6
  PortDeclarationDirection,
6
7
  )
7
8
  from classiq.interface.model.bind_operation import BindOperation
9
+ from classiq.interface.model.control import Control
8
10
  from classiq.interface.model.handle_binding import HandleBinding
9
11
  from classiq.interface.model.inplace_binary_operation import (
10
12
  BinaryOperation,
@@ -16,11 +18,7 @@ from classiq.interface.model.quantum_function_declaration import (
16
18
  NamedParamsQuantumFunctionDeclaration,
17
19
  )
18
20
  from classiq.interface.model.quantum_statement import QuantumStatement
19
- from classiq.interface.model.quantum_type import (
20
- QuantumBit,
21
- QuantumBitvector,
22
- QuantumNumeric,
23
- )
21
+ from classiq.interface.model.quantum_type import QuantumBitvector, QuantumNumeric
24
22
  from classiq.interface.model.variable_declaration_statement import (
25
23
  VariableDeclarationStatement,
26
24
  )
@@ -38,6 +36,7 @@ from classiq.model_expansions.scope import QuantumSymbol, Scope
38
36
  from classiq.qmod.builtins.functions import (
39
37
  CX,
40
38
  allocate,
39
+ apply_to_all,
41
40
  integer_xor,
42
41
  modular_add,
43
42
  modular_add_constant,
@@ -94,6 +93,18 @@ class InplaceBinaryOperationEmitter(Emitter[InplaceBinaryOperation]):
94
93
  handle=HandleBinding(name="target"),
95
94
  quantum_type=target_var.quantum_type,
96
95
  )
96
+ internal_func_decl = _binary_function_declaration(op.operation, constant=False)
97
+ if op.operation == BinaryOperation.Xor:
98
+ body = _build_inplace_xor_operation(
99
+ value_var=value_var,
100
+ target_var=target_var,
101
+ )
102
+ else:
103
+ body = _build_inplace_binary_operation(
104
+ value_var=value_var,
105
+ target_var=target_var,
106
+ internal_function_declaration=internal_func_decl,
107
+ )
97
108
  inplace_binary_op_function = FunctionClosure.create(
98
109
  name=op.operation.value,
99
110
  positional_arg_declarations=[
@@ -108,13 +119,7 @@ class InplaceBinaryOperationEmitter(Emitter[InplaceBinaryOperation]):
108
119
  direction=PortDeclarationDirection.Inout,
109
120
  ),
110
121
  ],
111
- body=_build_inplace_binary_operation(
112
- value_var=value_var,
113
- target_var=target_var,
114
- internal_function_declaration=_binary_function_declaration(
115
- op.operation, constant=False
116
- ),
117
- ),
122
+ body=body,
118
123
  scope=Scope(parent=self._current_scope),
119
124
  )
120
125
  with self._propagated_var_stack.capture_variables(op):
@@ -139,7 +144,7 @@ def _build_inplace_binary_operation(
139
144
  value_var: QuantumSymbol,
140
145
  target_var: QuantumSymbol,
141
146
  internal_function_declaration: NamedParamsQuantumFunctionDeclaration,
142
- ) -> List[QuantumStatement]:
147
+ ) -> list[QuantumStatement]:
143
148
  if TYPE_CHECKING:
144
149
  assert isinstance(value_var.quantum_type, QuantumNumeric)
145
150
  assert isinstance(target_var.quantum_type, QuantumNumeric)
@@ -148,9 +153,6 @@ def _build_inplace_binary_operation(
148
153
  value_var.quantum_type.fraction_digits_value
149
154
  - target_var.quantum_type.fraction_digits_value
150
155
  )
151
- size_diff = (
152
- value_var.quantum_type.size_in_bits - target_var.quantum_type.size_in_bits
153
- )
154
156
 
155
157
  target_overlap_var, target_var_decls, target_bind_ops = (
156
158
  _trim_superfluous_fraction_digits("target", target_var, -frac_digits_diff)
@@ -158,6 +160,10 @@ def _build_inplace_binary_operation(
158
160
  value_overlap_var, value_trim_var_decls, value_bind_ops = (
159
161
  _trim_superfluous_fraction_digits("value", value_var, frac_digits_diff)
160
162
  )
163
+ size_diff = (
164
+ value_overlap_var.quantum_type.size_in_bits
165
+ - target_overlap_var.quantum_type.size_in_bits
166
+ )
161
167
  (
162
168
  value_padded_var,
163
169
  value_pad_var_decls,
@@ -191,6 +197,54 @@ def _build_inplace_binary_operation(
191
197
  ]
192
198
 
193
199
 
200
+ def _build_inplace_xor_operation(
201
+ value_var: QuantumSymbol, target_var: QuantumSymbol
202
+ ) -> list[QuantumStatement]:
203
+ if TYPE_CHECKING:
204
+ assert isinstance(value_var.quantum_type, QuantumNumeric)
205
+ assert isinstance(target_var.quantum_type, QuantumNumeric)
206
+
207
+ frac_digits_diff = (
208
+ value_var.quantum_type.fraction_digits_value
209
+ - target_var.quantum_type.fraction_digits_value
210
+ )
211
+
212
+ target_overlap_var, target_var_decls, target_bind_ops = (
213
+ _trim_superfluous_fraction_digits("target", target_var, -frac_digits_diff)
214
+ )
215
+ value_overlap_var, value_trim_var_decls, value_bind_ops = (
216
+ _trim_superfluous_fraction_digits("value", value_var, frac_digits_diff)
217
+ )
218
+ target_left_var, value_left_var, sign_var_decls, sign_bind_ops, sign_xor = (
219
+ _split_and_xor_sign(target_overlap_var, value_overlap_var)
220
+ )
221
+
222
+ action: list[QuantumStatement] = []
223
+ if target_left_var is not None and value_left_var is not None:
224
+ action.append(
225
+ _internal_inplace_binary_operation_function_call(
226
+ integer_xor.func_decl,
227
+ value_left_var.handle,
228
+ target_left_var.handle,
229
+ )
230
+ )
231
+ action.extend(sign_xor)
232
+
233
+ return [
234
+ *target_var_decls,
235
+ *value_trim_var_decls,
236
+ *sign_var_decls,
237
+ WithinApply(
238
+ compute=[
239
+ *target_bind_ops,
240
+ *value_bind_ops,
241
+ *sign_bind_ops,
242
+ ],
243
+ action=action,
244
+ ),
245
+ ]
246
+
247
+
194
248
  def _internal_inplace_binary_operation_function_call(
195
249
  internal_function_declaration: NamedParamsQuantumFunctionDeclaration,
196
250
  value: Union[HandleBinding, Expression],
@@ -206,7 +260,7 @@ def _internal_inplace_binary_operation_function_call(
206
260
 
207
261
  def _trim_superfluous_fraction_digits(
208
262
  kind: str, var: QuantumSymbol, frac_digits_diff: int
209
- ) -> Tuple[QuantumSymbol, List[VariableDeclarationStatement], List[BindOperation]]:
263
+ ) -> tuple[QuantumSymbol, list[VariableDeclarationStatement], list[BindOperation]]:
210
264
  if frac_digits_diff <= 0:
211
265
  return var, [], []
212
266
 
@@ -245,12 +299,12 @@ def _trim_superfluous_fraction_digits(
245
299
  return overlap_var, split_var_declarations, [bind_op]
246
300
 
247
301
 
248
- def _pad_with_sign_bit(kind: str, var: QuantumSymbol, size_diff: int) -> Tuple[
302
+ def _pad_with_sign_bit(kind: str, var: QuantumSymbol, size_diff: int) -> tuple[
249
303
  QuantumSymbol,
250
- List[VariableDeclarationStatement],
251
- List[QuantumStatement],
252
- List[QuantumFunctionCall],
253
- List[BindOperation],
304
+ list[VariableDeclarationStatement],
305
+ list[QuantumStatement],
306
+ list[QuantumFunctionCall],
307
+ list[BindOperation],
254
308
  ]:
255
309
  quantum_type = var.quantum_type
256
310
  if TYPE_CHECKING:
@@ -290,7 +344,7 @@ def _pad_with_sign_bit(kind: str, var: QuantumSymbol, size_diff: int) -> Tuple[
290
344
  [padding_rebind],
291
345
  )
292
346
 
293
- significand_var, sign_var, sign_split_bind = _split_sign(kind, var)
347
+ significand_var, sign_var, sign_split_bind = _split_var(kind, var, 1)
294
348
  padding_init_ops = _init_padding(sign_var, padding_var, size_diff)
295
349
 
296
350
  padding_rebind = BindOperation(
@@ -317,7 +371,7 @@ def _pad_with_sign_bit(kind: str, var: QuantumSymbol, size_diff: int) -> Tuple[
317
371
 
318
372
  def _init_padding(
319
373
  sign_var: QuantumSymbol, padding_var: QuantumSymbol, size_diff: int
320
- ) -> List[QuantumFunctionCall]:
374
+ ) -> list[QuantumFunctionCall]:
321
375
  padding_init_ops = [
322
376
  QuantumFunctionCall(
323
377
  function=CX.func_decl.name,
@@ -332,7 +386,7 @@ def _init_padding(
332
386
 
333
387
  def _allocate_padding(
334
388
  kind: str, size_diff: int
335
- ) -> Tuple[QuantumSymbol, QuantumFunctionCall]:
389
+ ) -> tuple[QuantumSymbol, QuantumFunctionCall]:
336
390
  padding_var = QuantumSymbol(
337
391
  handle=HandleBinding(name=f"{kind}_sign_padding"),
338
392
  quantum_type=QuantumBitvector(
@@ -347,23 +401,95 @@ def _allocate_padding(
347
401
  return padding_var, padding_allocation
348
402
 
349
403
 
350
- def _split_sign(
351
- kind: str, var: QuantumSymbol
352
- ) -> Tuple[QuantumSymbol, QuantumSymbol, BindOperation]:
353
- significand_var = QuantumSymbol(
354
- handle=HandleBinding(name=f"{kind}_significand"),
404
+ def _split_var(
405
+ kind: str, var: QuantumSymbol, right_size: int
406
+ ) -> tuple[QuantumSymbol, QuantumSymbol, BindOperation]:
407
+ left_var = QuantumSymbol(
408
+ handle=HandleBinding(name=f"{kind}_left"),
355
409
  quantum_type=QuantumNumeric(
356
- size=Expression(expr=str(var.quantum_type.size_in_bits - 1)),
410
+ size=Expression(expr=str(var.quantum_type.size_in_bits - right_size)),
357
411
  is_signed=Expression(expr="False"),
358
412
  fraction_digits=Expression(expr="0"),
359
413
  ),
360
414
  )
361
- sign_var = QuantumSymbol(
362
- handle=HandleBinding(name=f"{kind}_sign_bit"),
363
- quantum_type=QuantumBit(),
415
+ right_var = QuantumSymbol(
416
+ handle=HandleBinding(name=f"{kind}_right"),
417
+ quantum_type=QuantumNumeric(
418
+ size=Expression(expr=str(right_size)),
419
+ is_signed=Expression(expr="False"),
420
+ fraction_digits=Expression(expr="0"),
421
+ ),
364
422
  )
365
- sign_split_bind = BindOperation(
423
+ split_bind = BindOperation(
366
424
  in_handles=[var.handle],
367
- out_handles=[significand_var.handle, sign_var.handle],
425
+ out_handles=[left_var.handle, right_var.handle],
426
+ )
427
+ return left_var, right_var, split_bind
428
+
429
+
430
+ def _split_and_xor_sign(target_var: QuantumSymbol, value_var: QuantumSymbol) -> tuple[
431
+ Optional[QuantumSymbol],
432
+ Optional[QuantumSymbol],
433
+ list[VariableDeclarationStatement],
434
+ list[BindOperation],
435
+ list[Control],
436
+ ]:
437
+ if TYPE_CHECKING:
438
+ assert isinstance(value_var.quantum_type, QuantumNumeric)
439
+ assert isinstance(target_var.quantum_type, QuantumNumeric)
440
+ size_diff = (
441
+ value_var.quantum_type.size_in_bits - target_var.quantum_type.size_in_bits
442
+ )
443
+ if not value_var.quantum_type.sign_value or size_diff >= 0:
444
+ return target_var, value_var, [], [], []
445
+
446
+ if value_var.quantum_type.size_in_bits == 1:
447
+ return None, None, [], [], [_xor_sign(target_var, value_var)]
448
+
449
+ value_rest_var, value_sign_var, value_split_bind = _split_var("value", value_var, 1)
450
+ target_left_var, target_right_var, target_split_bind = _split_var(
451
+ "target", target_var, -size_diff + 1
452
+ )
453
+ var_decls = [
454
+ VariableDeclarationStatement(
455
+ name=var.handle.name,
456
+ quantum_type=var.quantum_type,
457
+ )
458
+ for var in (value_rest_var, value_sign_var, target_left_var, target_right_var)
459
+ ]
460
+ bind_ops = [value_split_bind, target_split_bind]
461
+ sign_xor = _xor_sign(target_right_var, value_sign_var)
462
+ return target_left_var, value_rest_var, var_decls, bind_ops, [sign_xor]
463
+
464
+
465
+ def _xor_sign(target_var: QuantumSymbol, value_var: QuantumSymbol) -> Control:
466
+ quantum_type = value_var.quantum_type
467
+ if TYPE_CHECKING:
468
+ assert isinstance(quantum_type, QuantumNumeric)
469
+ if quantum_type.size_in_bits != 1 or quantum_type.fraction_digits_value not in (
470
+ 0,
471
+ 1,
472
+ ):
473
+ raise ClassiqInternalExpansionError
474
+
475
+ inner_xor = QuantumFunctionCall(
476
+ function=apply_to_all.func_decl.name,
477
+ positional_args=["X", target_var.handle],
478
+ )
479
+ inner_xor.set_func_decl(apply_to_all.func_decl)
480
+
481
+ if quantum_type.sign_value:
482
+ if quantum_type.fraction_digits_value == 1:
483
+ ctrl_value = -0.5
484
+ else:
485
+ ctrl_value = -1
486
+ else:
487
+ if quantum_type.fraction_digits_value == 1:
488
+ ctrl_value = 0.5
489
+ else:
490
+ ctrl_value = 1
491
+
492
+ return Control(
493
+ expression=Expression(expr=f"{value_var.handle} == {ctrl_value}"),
494
+ body=[inner_xor],
368
495
  )
369
- return significand_var, sign_var, sign_split_bind
@@ -1,4 +1,4 @@
1
- from typing import TYPE_CHECKING, Dict, List, Tuple
1
+ from typing import TYPE_CHECKING
2
2
 
3
3
  import sympy
4
4
  from sympy import sympify
@@ -108,8 +108,8 @@ class PhaseEmitter(ExpressionOperationEmitter[PhaseOperation]):
108
108
 
109
109
 
110
110
  def _get_single_bit_vars_expression(
111
- expr: sympy.Expr, vars_info: Dict[str, QuantumScalar]
112
- ) -> Tuple[sympy.Expr, List[sympy.Symbol]]:
111
+ expr: sympy.Expr, vars_info: dict[str, QuantumScalar]
112
+ ) -> tuple[sympy.Expr, list[sympy.Symbol]]:
113
113
  bit_vars = []
114
114
  for var_name, var_info in vars_info.items():
115
115
  size = var_info.size_in_bits
@@ -139,9 +139,9 @@ def _get_single_bit_vars_expression(
139
139
 
140
140
 
141
141
  def _convert_ising_sympy_to_pauli_terms(
142
- ising_expr: sympy.Expr, ordered_sympy_vars: List[sympy.Symbol]
142
+ ising_expr: sympy.Expr, ordered_sympy_vars: list[sympy.Symbol]
143
143
  ) -> str:
144
- pauli_terms: List[str] = []
144
+ pauli_terms: list[str] = []
145
145
  coefficients = ising_expr.as_coefficients_dict(*ordered_sympy_vars)
146
146
  for expr_term in ising_expr.args:
147
147
  expr_vars = _get_vars(expr_term)
@@ -171,7 +171,7 @@ def _convert_ising_sympy_to_pauli_terms(
171
171
 
172
172
  def _convert_cost_expression_to_hamiltonian(
173
173
  expr: str,
174
- vars: Dict[str, QuantumScalar],
174
+ vars: dict[str, QuantumScalar],
175
175
  ) -> Expression:
176
176
  sympy_expr = sympify(expr)
177
177
  single_bit_vars_expression, single_bit_vars = _get_single_bit_vars_expression(
@@ -1,6 +1,5 @@
1
1
  import ast
2
2
  import re
3
- from typing import Tuple
4
3
 
5
4
  from classiq.interface.exceptions import (
6
5
  ClassiqExpansionError,
@@ -23,6 +22,7 @@ from classiq.interface.model.quantum_expressions.quantum_expression import (
23
22
  from classiq.interface.model.quantum_function_call import QuantumFunctionCall
24
23
  from classiq.interface.model.quantum_type import (
25
24
  QuantumNumeric,
25
+ QuantumType,
26
26
  )
27
27
  from classiq.interface.model.variable_declaration_statement import (
28
28
  VariableDeclarationStatement,
@@ -41,6 +41,10 @@ from classiq.model_expansions.visitors.boolean_expression_transformers import (
41
41
  from classiq.qmod import builtins
42
42
  from classiq.qmod.builtins.functions import X, allocate
43
43
 
44
+ HANDLE_ERROR_MESSAGE = (
45
+ "Quantum variable '{handle_str}' cannot appear on both sides of the assignment"
46
+ )
47
+
44
48
 
45
49
  def _is_constant(expr: str) -> bool:
46
50
  try:
@@ -129,7 +133,7 @@ class QuantumAssignmentOperationEmitter(
129
133
 
130
134
  def _optimize_boolean_expression(
131
135
  self, op: ArithmeticOperation, expression: Expression
132
- ) -> Tuple[ArithmeticOperation, Expression, bool]:
136
+ ) -> tuple[ArithmeticOperation, Expression, bool]:
133
137
  if (
134
138
  self._interpreter._is_frontend
135
139
  or op.operation_kind
@@ -150,7 +154,7 @@ class QuantumAssignmentOperationEmitter(
150
154
 
151
155
  def _adapt_boolean_inplace(
152
156
  self, op: ArithmeticOperation, expression: Expression, is_bool_opt: bool
153
- ) -> Tuple[ArithmeticOperation, Expression, bool]:
157
+ ) -> tuple[ArithmeticOperation, Expression, bool]:
154
158
  adapter = BooleanExpressionFuncLibAdapter(is_bool_opt)
155
159
  adapted_expression = self._evaluate_expression(
156
160
  Expression(expr=ast.unparse(adapter.visit(ast.parse(expression.expr))))
@@ -223,12 +227,28 @@ class QuantumAssignmentOperationEmitter(
223
227
  self._interpreter.emit_statement(allocate_call)
224
228
  return True
225
229
 
230
+ @staticmethod
231
+ def _get_updated_op_split_symbols(
232
+ op: QuantumAssignmentOperation,
233
+ symbol_mapping: dict[HandleBinding, tuple[str, QuantumType]],
234
+ ) -> QuantumAssignmentOperation:
235
+ if op.result_var not in symbol_mapping:
236
+ return op
237
+ handle_str, quantum_type = symbol_mapping[op.result_var]
238
+ if handle_str in op.expression.expr:
239
+ raise ClassiqExpansionError(
240
+ HANDLE_ERROR_MESSAGE.format(handle_str=str(op.result_var))
241
+ )
242
+ new_result_handle = HandleBinding(name=handle_str)
243
+ return op.model_copy(
244
+ update=dict(result_var=new_result_handle, _result_type=quantum_type)
245
+ )
246
+
226
247
 
227
248
  def _validate_naive_inplace_handles(qe: ArithmeticOperation) -> None:
228
249
  if qe.result_var in qe.var_handles:
229
250
  raise ClassiqExpansionError(
230
- f"Quantum variable {qe.result_var.name} cannot appear on both sides of "
231
- f"the ^= assignment"
251
+ HANDLE_ERROR_MESSAGE.format(handle_str=str(qe.result_var))
232
252
  )
233
253
 
234
254