classiq 0.83.0__py3-none-any.whl → 0.85.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (103) hide show
  1. classiq/_internals/api_wrapper.py +27 -0
  2. classiq/applications/chemistry/chemistry_model_constructor.py +0 -2
  3. classiq/applications/chemistry/hartree_fock.py +68 -0
  4. classiq/applications/chemistry/mapping.py +85 -0
  5. classiq/applications/chemistry/op_utils.py +79 -0
  6. classiq/applications/chemistry/problems.py +195 -0
  7. classiq/applications/chemistry/ucc.py +109 -0
  8. classiq/applications/chemistry/z2_symmetries.py +368 -0
  9. classiq/applications/combinatorial_helpers/pauli_helpers/pauli_utils.py +30 -1
  10. classiq/applications/combinatorial_optimization/combinatorial_problem.py +20 -42
  11. classiq/{model_expansions/evaluators → evaluators}/arg_type_match.py +12 -4
  12. classiq/{model_expansions/evaluators → evaluators}/argument_types.py +1 -1
  13. classiq/evaluators/classical_expression.py +53 -0
  14. classiq/{model_expansions/evaluators → evaluators}/classical_type_inference.py +3 -4
  15. classiq/{model_expansions/evaluators → evaluators}/parameter_types.py +17 -15
  16. classiq/execution/__init__.py +12 -1
  17. classiq/execution/execution_session.py +238 -49
  18. classiq/execution/jobs.py +26 -1
  19. classiq/execution/qnn.py +2 -2
  20. classiq/execution/user_budgets.py +39 -0
  21. classiq/interface/_version.py +1 -1
  22. classiq/interface/constants.py +1 -0
  23. classiq/interface/debug_info/debug_info.py +0 -4
  24. classiq/interface/execution/primitives.py +29 -1
  25. classiq/interface/executor/estimate_cost.py +35 -0
  26. classiq/interface/executor/execution_result.py +13 -0
  27. classiq/interface/executor/result.py +116 -1
  28. classiq/interface/executor/user_budget.py +26 -33
  29. classiq/interface/generator/expressions/atomic_expression_functions.py +10 -1
  30. classiq/interface/generator/expressions/proxies/classical/any_classical_value.py +0 -6
  31. classiq/interface/generator/functions/builtins/internal_operators.py +2 -0
  32. classiq/interface/generator/functions/classical_type.py +2 -35
  33. classiq/interface/generator/functions/concrete_types.py +20 -3
  34. classiq/interface/generator/functions/type_modifier.py +0 -19
  35. classiq/interface/generator/generated_circuit_data.py +5 -18
  36. classiq/interface/generator/types/compilation_metadata.py +0 -3
  37. classiq/interface/ide/operation_registry.py +45 -0
  38. classiq/interface/ide/visual_model.py +68 -3
  39. classiq/interface/model/bounds.py +12 -2
  40. classiq/interface/model/model.py +12 -7
  41. classiq/interface/model/port_declaration.py +2 -24
  42. classiq/interface/model/quantum_expressions/arithmetic_operation.py +7 -4
  43. classiq/interface/model/variable_declaration_statement.py +33 -6
  44. classiq/interface/pretty_print/__init__.py +0 -0
  45. classiq/{qmod/native → interface/pretty_print}/expression_to_qmod.py +18 -11
  46. classiq/interface/server/routes.py +4 -0
  47. classiq/model_expansions/atomic_expression_functions_defs.py +47 -6
  48. classiq/model_expansions/function_builder.py +4 -1
  49. classiq/model_expansions/interpreters/base_interpreter.py +3 -3
  50. classiq/model_expansions/interpreters/generative_interpreter.py +16 -1
  51. classiq/model_expansions/quantum_operations/allocate.py +1 -1
  52. classiq/model_expansions/quantum_operations/assignment_result_processor.py +64 -22
  53. classiq/model_expansions/quantum_operations/bind.py +2 -2
  54. classiq/model_expansions/quantum_operations/bounds.py +7 -1
  55. classiq/model_expansions/quantum_operations/call_emitter.py +26 -20
  56. classiq/model_expansions/quantum_operations/classical_var_emitter.py +16 -0
  57. classiq/model_expansions/quantum_operations/variable_decleration.py +31 -11
  58. classiq/model_expansions/scope.py +7 -0
  59. classiq/model_expansions/scope_initialization.py +3 -3
  60. classiq/model_expansions/transformers/model_renamer.py +6 -4
  61. classiq/model_expansions/transformers/type_modifier_inference.py +81 -43
  62. classiq/model_expansions/transformers/var_splitter.py +1 -1
  63. classiq/model_expansions/visitors/symbolic_param_inference.py +2 -3
  64. classiq/open_library/functions/__init__.py +3 -2
  65. classiq/open_library/functions/amplitude_amplification.py +10 -18
  66. classiq/open_library/functions/discrete_sine_cosine_transform.py +5 -5
  67. classiq/open_library/functions/grover.py +14 -6
  68. classiq/open_library/functions/modular_exponentiation.py +22 -20
  69. classiq/open_library/functions/qaoa_penalty.py +8 -1
  70. classiq/open_library/functions/state_preparation.py +18 -32
  71. classiq/qmod/__init__.py +2 -0
  72. classiq/qmod/builtins/enums.py +23 -0
  73. classiq/qmod/builtins/functions/__init__.py +2 -0
  74. classiq/qmod/builtins/functions/exponentiation.py +32 -4
  75. classiq/qmod/builtins/operations.py +65 -1
  76. classiq/qmod/builtins/structs.py +55 -3
  77. classiq/qmod/classical_variable.py +74 -0
  78. classiq/qmod/declaration_inferrer.py +3 -2
  79. classiq/qmod/native/pretty_printer.py +20 -20
  80. classiq/qmod/pretty_print/expression_to_python.py +2 -1
  81. classiq/qmod/pretty_print/pretty_printer.py +35 -21
  82. classiq/qmod/python_classical_type.py +12 -5
  83. classiq/qmod/qfunc.py +2 -19
  84. classiq/qmod/qmod_constant.py +2 -5
  85. classiq/qmod/qmod_parameter.py +2 -5
  86. classiq/qmod/qmod_variable.py +61 -23
  87. classiq/qmod/quantum_expandable.py +5 -3
  88. classiq/qmod/quantum_function.py +49 -4
  89. classiq/qmod/semantics/annotation/qstruct_annotator.py +1 -1
  90. classiq/qmod/semantics/validation/main_validation.py +1 -9
  91. classiq/qmod/symbolic_type.py +2 -1
  92. classiq/qmod/utilities.py +0 -2
  93. classiq/qmod/write_qmod.py +1 -1
  94. {classiq-0.83.0.dist-info → classiq-0.85.0.dist-info}/METADATA +4 -1
  95. {classiq-0.83.0.dist-info → classiq-0.85.0.dist-info}/RECORD +101 -90
  96. classiq/interface/model/quantum_variable_declaration.py +0 -7
  97. classiq/model_expansions/evaluators/classical_expression.py +0 -36
  98. /classiq/{model_expansions/evaluators → evaluators}/__init__.py +0 -0
  99. /classiq/{model_expansions/evaluators → evaluators}/control.py +0 -0
  100. /classiq/{model_expansions → evaluators}/expression_evaluator.py +0 -0
  101. /classiq/{model_expansions/evaluators → evaluators}/quantum_type_utils.py +0 -0
  102. /classiq/{model_expansions/evaluators → evaluators}/type_type_match.py +0 -0
  103. {classiq-0.83.0.dist-info → classiq-0.85.0.dist-info}/WHEEL +0 -0
@@ -1,10 +1,12 @@
1
- from typing import Optional
1
+ from typing import TYPE_CHECKING, Optional
2
2
 
3
3
  from classiq.interface.exceptions import ClassiqExpansionError
4
4
  from classiq.interface.generator.arith.arithmetic import compute_arithmetic_result_type
5
5
  from classiq.interface.generator.expressions.expression import Expression
6
6
  from classiq.interface.model.allocate import Allocate
7
7
  from classiq.interface.model.bind_operation import BindOperation
8
+ from classiq.interface.model.block import Block
9
+ from classiq.interface.model.bounds import SetBoundsStatement
8
10
  from classiq.interface.model.handle_binding import (
9
11
  ConcreteHandleBinding,
10
12
  HandleBinding,
@@ -19,25 +21,37 @@ from classiq.interface.model.quantum_expressions.quantum_expression import (
19
21
  )
20
22
  from classiq.interface.model.quantum_function_call import QuantumFunctionCall
21
23
  from classiq.interface.model.quantum_type import QuantumBitvector, QuantumNumeric
24
+ from classiq.interface.model.statement_block import StatementBlock
22
25
  from classiq.interface.model.variable_declaration_statement import (
23
26
  VariableDeclarationStatement,
24
27
  )
25
28
  from classiq.interface.model.within_apply_operation import WithinApply
26
29
 
27
- from classiq.model_expansions.evaluators.quantum_type_utils import copy_type_information
30
+ from classiq.evaluators.quantum_type_utils import copy_type_information
28
31
  from classiq.model_expansions.quantum_operations.arithmetic.explicit_boolean_expressions import (
29
32
  convert_assignment_bool_expression,
30
33
  validate_assignment_bool_expression,
31
34
  )
32
35
  from classiq.model_expansions.quantum_operations.emitter import Emitter
33
- from classiq.model_expansions.scope import QuantumSymbol
36
+ from classiq.model_expansions.scope import ClassicalSymbol
34
37
  from classiq.model_expansions.transformers.ast_renamer import rename_variables
35
38
  from classiq.qmod.builtins.functions.standard_gates import CX
36
39
 
40
+ if TYPE_CHECKING:
41
+ from classiq.model_expansions.interpreters.base_interpreter import BaseInterpreter
42
+
37
43
 
38
44
  class AssignmentResultProcessor(Emitter[QuantumAssignmentOperation]):
45
+ def __init__(
46
+ self, interpreter: "BaseInterpreter", replace_assignment_if_needed: bool = False
47
+ ) -> None:
48
+ super().__init__(interpreter)
49
+ self._replace_assignment_if_needed = replace_assignment_if_needed
50
+
39
51
  def emit(self, op: QuantumAssignmentOperation, /) -> bool:
40
- result_symbol = self._interpreter.evaluate(op.result_var).as_type(QuantumSymbol)
52
+ result_symbol = self._interpreter.evaluate(op.result_var).value
53
+ if isinstance(result_symbol, ClassicalSymbol):
54
+ return False
41
55
  result_type = result_symbol.quantum_type
42
56
 
43
57
  if not (
@@ -70,9 +84,11 @@ class AssignmentResultProcessor(Emitter[QuantumAssignmentOperation]):
70
84
  self._validate_declared_attributes(
71
85
  result_type, inferred_result_type, str(op.result_var)
72
86
  )
73
- self._assign_to_inferred_var_and_bind(op, result_type, inferred_result_type)
74
- result_type.set_bounds(inferred_result_type.get_bounds())
75
- return True
87
+ if self._replace_assignment_if_needed:
88
+ self._assign_to_inferred_var_and_bind(op, result_type, inferred_result_type)
89
+ return True
90
+ else:
91
+ return False
76
92
 
77
93
  def _infer_result_type(self, op: ArithmeticOperation) -> Optional[QuantumNumeric]:
78
94
  expr = self._evaluate_expression(op.expression)
@@ -182,6 +198,7 @@ class AssignmentResultProcessor(Emitter[QuantumAssignmentOperation]):
182
198
  result_type: QuantumNumeric,
183
199
  inferred_result_type: QuantumNumeric,
184
200
  ) -> None:
201
+ stmts: StatementBlock = []
185
202
  handles: list[HandleBinding] = []
186
203
 
187
204
  extra_fraction_digits = (
@@ -190,20 +207,22 @@ class AssignmentResultProcessor(Emitter[QuantumAssignmentOperation]):
190
207
  )
191
208
  if extra_fraction_digits > 0:
192
209
  handles.append(
193
- self._declare_qarray("extra_fraction_digits", extra_fraction_digits)
210
+ self._declare_qarray(
211
+ "extra_fraction_digits", extra_fraction_digits, stmts
212
+ )
194
213
  )
195
214
 
196
215
  inferred_result_name = self._counted_name_allocator.allocate("inferred_result")
197
216
  inferred_result_handle = HandleBinding(name=inferred_result_name)
198
- self._interpreter.emit(
217
+ stmts.append(
199
218
  VariableDeclarationStatement(
200
- name=inferred_result_name, quantum_type=inferred_result_type
219
+ name=inferred_result_name, qmod_type=inferred_result_type
201
220
  )
202
221
  )
203
222
  handles.append(inferred_result_handle)
204
223
  modified_op = op.model_copy(update={"result_var": inferred_result_handle})
205
224
  self._interpreter.add_to_debug_info(modified_op)
206
- self._interpreter.emit(modified_op)
225
+ stmts.append(modified_op)
207
226
 
208
227
  result_integer_size = (
209
228
  result_type.size_in_bits - result_type.fraction_digits_value
@@ -214,11 +233,11 @@ class AssignmentResultProcessor(Emitter[QuantumAssignmentOperation]):
214
233
  )
215
234
  extra_integers = result_integer_size - inferred_result_integer_size
216
235
  if extra_integers > 0:
217
- handles.append(self._declare_qarray("extra_integers", extra_integers))
236
+ handles.append(
237
+ self._declare_qarray("extra_integers", extra_integers, stmts)
238
+ )
218
239
 
219
- self._interpreter.emit(
220
- BindOperation(in_handles=handles, out_handles=[op.result_var])
221
- )
240
+ stmts.append(BindOperation(in_handles=handles, out_handles=[op.result_var]))
222
241
 
223
242
  if (
224
243
  result_type.sign_value
@@ -226,22 +245,44 @@ class AssignmentResultProcessor(Emitter[QuantumAssignmentOperation]):
226
245
  and extra_integers > 0
227
246
  ):
228
247
  sign_idx = result_type.size_in_bits - extra_integers - 1
229
- self._sign_extension(op.result_var, sign_idx, result_type.size_in_bits)
248
+ self._sign_extension(
249
+ op.result_var, sign_idx, result_type.size_in_bits, stmts
250
+ )
251
+
252
+ if (inferred_bounds := inferred_result_type.get_bounds()) is not None:
253
+ lower_bound = Expression(expr=str(inferred_bounds[0]))
254
+ upper_bound = Expression(expr=str(inferred_bounds[1]))
255
+ else:
256
+ lower_bound, upper_bound = None, None
257
+ stmts.append(
258
+ SetBoundsStatement(
259
+ target=op.result_var,
260
+ lower_bound=lower_bound,
261
+ upper_bound=upper_bound,
262
+ )
263
+ )
264
+
265
+ self._interpreter.emit(
266
+ Block(
267
+ statements=stmts,
268
+ uuid=op.uuid,
269
+ back_ref=op.back_ref,
270
+ )
271
+ )
230
272
 
231
273
  def _declare_qarray(
232
274
  self,
233
275
  prefix: str,
234
276
  size: int,
277
+ stmts: StatementBlock,
235
278
  allocate: bool = True,
236
279
  ) -> HandleBinding:
237
280
  name = self._counted_name_allocator.allocate(prefix)
238
281
  handle = HandleBinding(name=name)
239
282
  quantum_type = QuantumBitvector(length=Expression(expr=str(size)))
240
- self._interpreter.emit(
241
- VariableDeclarationStatement(name=name, quantum_type=quantum_type)
242
- )
283
+ stmts.append(VariableDeclarationStatement(name=name, qmod_type=quantum_type))
243
284
  if allocate:
244
- self._interpreter.emit(Allocate(target=handle))
285
+ stmts.append(Allocate(target=handle))
245
286
  return handle
246
287
 
247
288
  def _sign_extension(
@@ -249,9 +290,10 @@ class AssignmentResultProcessor(Emitter[QuantumAssignmentOperation]):
249
290
  result_var: ConcreteHandleBinding,
250
291
  sign_idx: int,
251
292
  size: int,
293
+ stmts: StatementBlock,
252
294
  ) -> None:
253
- aux = self._declare_qarray("inferred_result_aux", size, allocate=False)
254
- self._interpreter.emit(
295
+ aux = self._declare_qarray("inferred_result_aux", size, stmts, allocate=False)
296
+ stmts.append(
255
297
  WithinApply(
256
298
  compute=[BindOperation(in_handles=[result_var], out_handles=[aux])],
257
299
  action=[
@@ -8,10 +8,10 @@ from classiq.interface.exceptions import (
8
8
  from classiq.interface.model.bind_operation import BindOperation
9
9
  from classiq.interface.model.quantum_type import QuantumNumeric
10
10
 
11
- from classiq.model_expansions.evaluators.parameter_types import (
11
+ from classiq.evaluators.parameter_types import (
12
12
  evaluate_types_in_quantum_symbols,
13
13
  )
14
- from classiq.model_expansions.evaluators.quantum_type_utils import (
14
+ from classiq.evaluators.quantum_type_utils import (
15
15
  set_size,
16
16
  validate_bind_targets,
17
17
  )
@@ -24,7 +24,13 @@ class SetBoundsEmitter(Emitter[SetBoundsStatement]):
24
24
  raise ClassiqExpansionError(
25
25
  f"Cannot set bounds of a non-numeric variable {op.target.qmod_expr!r}"
26
26
  )
27
- target.quantum_type.set_bounds(op.bounds)
27
+
28
+ if op.lower_bound is not None and op.upper_bound is not None:
29
+ target.quantum_type.set_bounds(
30
+ (op.lower_bound.to_float_value(), op.upper_bound.to_float_value())
31
+ )
32
+ else:
33
+ target.quantum_type.reset_bounds()
28
34
  if self._keep_statement:
29
35
  self.emit_statement(op)
30
36
  return True
@@ -50,19 +50,19 @@ from classiq.interface.model.variable_declaration_statement import (
50
50
  VariableDeclarationStatement,
51
51
  )
52
52
 
53
+ from classiq.evaluators.argument_types import (
54
+ add_information_from_output_arguments,
55
+ handle_args_numeric_bounds,
56
+ )
57
+ from classiq.evaluators.parameter_types import (
58
+ evaluate_parameter_types_from_args,
59
+ )
53
60
  from classiq.model_expansions.capturing.captured_vars import (
54
61
  INITIALIZED_VAR_MESSAGE,
55
62
  UNINITIALIZED_VAR_MESSAGE,
56
63
  validate_args_are_not_propagated,
57
64
  )
58
65
  from classiq.model_expansions.closure import Closure, FunctionClosure
59
- from classiq.model_expansions.evaluators.argument_types import (
60
- add_information_from_output_arguments,
61
- handle_args_numeric_bounds,
62
- )
63
- from classiq.model_expansions.evaluators.parameter_types import (
64
- evaluate_parameter_types_from_args,
65
- )
66
66
  from classiq.model_expansions.function_builder import (
67
67
  FunctionContext,
68
68
  )
@@ -135,13 +135,13 @@ def _validate_gen_args(
135
135
  ):
136
136
  if (
137
137
  isinstance(param, ClassicalParameterDeclaration)
138
- and param.classical_type.is_purely_generative
138
+ and not param.classical_type.is_purely_declarative
139
139
  and _is_symbolic(arg.value)
140
140
  ):
141
+ readable_expr = transform_expression(str(arg.value), {}, {}, one_line=True)
141
142
  raise ClassiqExpansionError(
142
- f"Parameter {param.name!r} is used in a compile-time expression "
143
- f"context but is passed a runtime expression "
144
- f"{transform_expression(str(arg.value), {}, {}, one_line=True)!r}"
143
+ f"Cannot pass symbolic expression {readable_expr!r} as Python-type "
144
+ f"parameter {param.name!r}"
145
145
  )
146
146
 
147
147
 
@@ -209,17 +209,21 @@ class CallEmitter(Generic[QuantumStatementT], Emitter[QuantumStatementT], VarSpl
209
209
  function.name, new_declaration
210
210
  )
211
211
  else:
212
- # FIXME: enable for BE (CLS-2390)
213
- if type(self._interpreter).__name__ == "FrontendGenerativeInterpreter":
214
- _validate_gen_args(function, evaluated_args)
212
+ _validate_gen_args(function, evaluated_args)
215
213
  new_declaration = self._expand_function(
216
214
  evaluated_args, new_declaration, function
217
215
  )
218
216
  new_positional_arg_decls = new_declaration.positional_arg_declarations
219
217
  evaluated_args = [
220
218
  arg
221
- for arg in evaluated_args
222
- if isinstance(arg.value, QuantumVariable) or _is_symbolic(arg.value)
219
+ for param, arg in zip_strict(
220
+ function.positional_arg_declarations, evaluated_args, strict=True
221
+ )
222
+ if isinstance(arg.value, QuantumVariable)
223
+ or (
224
+ isinstance(param, ClassicalParameterDeclaration)
225
+ and param.classical_type.is_purely_declarative
226
+ )
223
227
  ]
224
228
 
225
229
  add_information_from_output_arguments(new_positional_arg_decls, evaluated_args)
@@ -312,7 +316,7 @@ class CallEmitter(Generic[QuantumStatementT], Emitter[QuantumStatementT], VarSpl
312
316
  if isinstance(param, PortDeclaration)
313
317
  or (
314
318
  isinstance(param, ClassicalParameterDeclaration)
315
- and _is_symbolic(arg.value)
319
+ and param.classical_type.is_purely_declarative
316
320
  )
317
321
  ]
318
322
  func_def = self._builder.create_definition(function_context, params)
@@ -350,8 +354,10 @@ class CallEmitter(Generic[QuantumStatementT], Emitter[QuantumStatementT], VarSpl
350
354
  ),
351
355
  defining_function=closure,
352
356
  )
353
- elif _is_symbolic(argument.value):
354
- assert isinstance(parameter, ClassicalParameterDeclaration)
357
+ elif (
358
+ isinstance(parameter, ClassicalParameterDeclaration)
359
+ and parameter.classical_type.is_purely_declarative
360
+ ):
355
361
  inferred_arg = Evaluated(
356
362
  value=parameter.classical_type.get_classical_proxy(param_handle),
357
363
  defining_function=closure,
@@ -426,7 +432,7 @@ class CallEmitter(Generic[QuantumStatementT], Emitter[QuantumStatementT], VarSpl
426
432
  ).unchecked
427
433
  TypeModifierValidation(
428
434
  skip_validation=self._interpreter.skip_type_modifier_validation
429
- ).run(func_def.port_declarations, func_def.body, unchecked)
435
+ ).run(func_def, unchecked)
430
436
 
431
437
  @staticmethod
432
438
  def _should_override_type_modifiers(func_context: FunctionContext) -> bool:
@@ -0,0 +1,16 @@
1
+ from classiq.interface.model.quantum_expressions.arithmetic_operation import (
2
+ ArithmeticOperation,
3
+ )
4
+
5
+ from classiq.model_expansions.quantum_operations.emitter import Emitter
6
+ from classiq.model_expansions.scope import ClassicalSymbol
7
+
8
+
9
+ class ClassicalVarEmitter(Emitter[ArithmeticOperation]):
10
+ def emit(self, op: ArithmeticOperation, /) -> bool:
11
+ result_symbol = self._interpreter.evaluate(op.result_var).value
12
+ if not isinstance(result_symbol, ClassicalSymbol):
13
+ return False
14
+ op._classical_assignment = True
15
+ self.emit_statement(op)
16
+ return True
@@ -1,14 +1,19 @@
1
+ from typing import TYPE_CHECKING, Union
2
+
1
3
  from classiq.interface.exceptions import ClassiqExpansionError
4
+ from classiq.interface.generator.functions.classical_type import ClassicalType
2
5
  from classiq.interface.model.handle_binding import HandleBinding
6
+ from classiq.interface.model.quantum_type import QuantumType
3
7
  from classiq.interface.model.variable_declaration_statement import (
4
8
  VariableDeclarationStatement,
5
9
  )
6
10
 
7
- from classiq.model_expansions.evaluators.parameter_types import (
11
+ from classiq.evaluators.parameter_types import (
12
+ evaluate_type_in_classical_symbol,
8
13
  evaluate_type_in_quantum_symbol,
9
14
  )
10
15
  from classiq.model_expansions.quantum_operations.emitter import Emitter
11
- from classiq.model_expansions.scope import Evaluated, QuantumSymbol
16
+ from classiq.model_expansions.scope import ClassicalSymbol, Evaluated, QuantumSymbol
12
17
 
13
18
 
14
19
  class VariableDeclarationStatementEmitter(Emitter[VariableDeclarationStatement]):
@@ -16,24 +21,39 @@ class VariableDeclarationStatementEmitter(Emitter[VariableDeclarationStatement])
16
21
  var_decl = variable_declaration.model_copy(
17
22
  update=dict(back_ref=variable_declaration.uuid)
18
23
  )
19
- var_decl.quantum_type = variable_declaration.quantum_type.model_copy()
24
+ var_decl.qmod_type = variable_declaration.qmod_type.model_copy()
20
25
  if variable_declaration.name in self._current_scope:
21
26
  raise ClassiqExpansionError(
22
27
  f"Variable {variable_declaration.name!r} is already defined"
23
28
  )
24
- self._current_scope[variable_declaration.name] = Evaluated(
25
- value=QuantumSymbol(
29
+ var_value: Union[QuantumSymbol, ClassicalSymbol]
30
+ if variable_declaration.is_quantum:
31
+ if TYPE_CHECKING:
32
+ assert isinstance(var_decl.qmod_type, QuantumType)
33
+ var_value = QuantumSymbol(
26
34
  handle=HandleBinding(name=var_decl.name),
27
35
  quantum_type=evaluate_type_in_quantum_symbol(
28
- var_decl.quantum_type,
36
+ var_decl.qmod_type,
29
37
  self._current_scope,
30
38
  var_decl.name,
31
39
  ),
32
- ),
33
- defining_function=self._builder.current_function,
34
- )
35
- self._builder.current_block.captured_vars.init_var(
36
- var_decl.name, self._builder.current_function
40
+ )
41
+ self._builder.current_block.captured_vars.init_var(
42
+ var_decl.name, self._builder.current_function
43
+ )
44
+ else:
45
+ if TYPE_CHECKING:
46
+ assert isinstance(var_decl.qmod_type, ClassicalType)
47
+ var_value = ClassicalSymbol(
48
+ handle=HandleBinding(name=var_decl.name),
49
+ classical_type=evaluate_type_in_classical_symbol(
50
+ var_decl.qmod_type,
51
+ self._current_scope,
52
+ var_decl.name,
53
+ ),
54
+ )
55
+ self._current_scope[variable_declaration.name] = Evaluated(
56
+ value=var_value, defining_function=self._builder.current_function
37
57
  )
38
58
  self.emit_statement(var_decl)
39
59
  return True
@@ -21,6 +21,7 @@ from classiq.interface.generator.expressions.proxies.classical.classical_scalar_
21
21
  from classiq.interface.generator.expressions.proxies.classical.qmod_struct_instance import (
22
22
  QmodStructInstance,
23
23
  )
24
+ from classiq.interface.generator.functions.classical_type import ClassicalType
24
25
  from classiq.interface.generator.functions.type_name import TypeName
25
26
  from classiq.interface.helpers.text_utils import readable_list, s
26
27
  from classiq.interface.model.handle_binding import (
@@ -202,6 +203,12 @@ class QuantumSymbolList(QuantumVariable):
202
203
  return str(self.handles)
203
204
 
204
205
 
206
+ @dataclass(frozen=True)
207
+ class ClassicalSymbol:
208
+ handle: HandleBinding
209
+ classical_type: ClassicalType
210
+
211
+
205
212
  @singledispatch
206
213
  def evaluated_to_str(value: Any) -> str:
207
214
  return str(value)
@@ -11,13 +11,13 @@ from classiq.interface.model.native_function_definition import NativeFunctionDef
11
11
  from classiq.interface.model.port_declaration import PortDeclaration
12
12
  from classiq.interface.model.quantum_function_declaration import PositionalArg
13
13
 
14
- from classiq.model_expansions.closure import FunctionClosure, GenerativeFunctionClosure
15
- from classiq.model_expansions.evaluators.classical_expression import (
14
+ from classiq.evaluators.classical_expression import (
16
15
  evaluate_classical_expression,
17
16
  )
18
- from classiq.model_expansions.evaluators.parameter_types import (
17
+ from classiq.evaluators.parameter_types import (
19
18
  evaluate_type_in_quantum_symbol,
20
19
  )
20
+ from classiq.model_expansions.closure import FunctionClosure, GenerativeFunctionClosure
21
21
  from classiq.model_expansions.scope import Evaluated, QuantumSymbol, Scope
22
22
  from classiq.qmod.builtins import BUILTIN_CONSTANTS
23
23
  from classiq.qmod.builtins.enums import BUILTIN_ENUM_DECLARATIONS
@@ -77,7 +77,7 @@ class HandleRenaming:
77
77
  SymbolRenaming = Mapping[HandleBinding, Sequence[HandleRenaming]]
78
78
 
79
79
 
80
- def _rewrite_expression(
80
+ def rewrite_expression(
81
81
  symbol_mapping: SymbolRenaming, expression: Expression
82
82
  ) -> Expression:
83
83
  normalized_expr = ExprNormalizer().visit(ast.parse(expression.expr))
@@ -88,7 +88,8 @@ def _rewrite_expression(
88
88
 
89
89
  handle_names = {
90
90
  part.source_handle: part.target_var_handle
91
- for parts in symbol_mapping.values()
91
+ for source, parts in symbol_mapping.items()
92
+ if source.name in expression.expr
92
93
  for part in parts
93
94
  }
94
95
  new_expr_str = ast.unparse(normalized_expr)
@@ -101,7 +102,8 @@ def _rewrite_expression(
101
102
  for handle in sorted_handles:
102
103
  new_handle = handle.collapse()
103
104
  for handle_to_replace, replacement in handle_names.items():
104
- new_handle = new_handle.replace_prefix(handle_to_replace, replacement)
105
+ if new_handle.name == handle_to_replace.name:
106
+ new_handle = new_handle.replace_prefix(handle_to_replace, replacement)
105
107
  new_expr_str = _replace_full_word(str(handle), str(new_handle), new_expr_str)
106
108
 
107
109
  new_expr = Expression(expr=new_expr_str)
@@ -132,7 +134,7 @@ class _ReplaceSplitVarsExpressions(ModelTransformer):
132
134
  self._symbol_mapping = symbol_mapping
133
135
 
134
136
  def visit_Expression(self, expr: Expression) -> Expression:
135
- return _rewrite_expression(self._symbol_mapping, expr)
137
+ return rewrite_expression(self._symbol_mapping, expr)
136
138
 
137
139
  def visit_QuantumExpressionOperation(
138
140
  self, op: QuantumExpressionOperation