classiq 0.56.1__py3-none-any.whl → 0.57.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 (31) hide show
  1. classiq/analyzer/show_interactive_hack.py +16 -4
  2. classiq/executor.py +1 -1
  3. classiq/interface/_version.py +1 -1
  4. classiq/interface/executor/execution_request.py +5 -5
  5. classiq/interface/generator/arith/arithmetic_expression_validator.py +28 -9
  6. classiq/interface/generator/types/builtin_enum_declarations.py +1 -0
  7. classiq/model_expansions/closure.py +24 -6
  8. classiq/model_expansions/quantum_operations/call_emitter.py +207 -0
  9. classiq/model_expansions/quantum_operations/classicalif.py +2 -2
  10. classiq/model_expansions/quantum_operations/control.py +7 -5
  11. classiq/model_expansions/quantum_operations/emitter.py +1 -186
  12. classiq/model_expansions/quantum_operations/expression_operation.py +26 -189
  13. classiq/model_expansions/quantum_operations/inplace_binary_operation.py +2 -2
  14. classiq/model_expansions/quantum_operations/invert.py +2 -2
  15. classiq/model_expansions/quantum_operations/phase.py +3 -1
  16. classiq/model_expansions/quantum_operations/power.py +2 -2
  17. classiq/model_expansions/quantum_operations/quantum_assignment_operation.py +7 -9
  18. classiq/model_expansions/quantum_operations/quantum_function_call.py +2 -2
  19. classiq/model_expansions/quantum_operations/repeat.py +2 -2
  20. classiq/model_expansions/transformers/__init__.py +0 -0
  21. classiq/model_expansions/transformers/var_splitter.py +237 -0
  22. classiq/qmod/builtins/classical_functions.py +1 -0
  23. classiq/qmod/builtins/functions/state_preparation.py +1 -1
  24. classiq/qmod/create_model_function.py +25 -20
  25. classiq/qmod/pretty_print/pretty_printer.py +53 -28
  26. classiq/qmod/qfunc.py +18 -16
  27. classiq/qmod/quantum_function.py +30 -24
  28. classiq/synthesis.py +3 -1
  29. {classiq-0.56.1.dist-info → classiq-0.57.0.dist-info}/METADATA +1 -1
  30. {classiq-0.56.1.dist-info → classiq-0.57.0.dist-info}/RECORD +31 -28
  31. {classiq-0.56.1.dist-info → classiq-0.57.0.dist-info}/WHEEL +0 -0
@@ -1,61 +1,38 @@
1
1
  from abc import abstractmethod
2
- from collections.abc import Sequence
3
2
  from typing import (
4
3
  TYPE_CHECKING,
5
4
  Generic,
6
5
  Optional,
7
6
  TypeVar,
8
7
  Union,
9
- cast,
10
8
  )
11
9
 
12
10
  import sympy
13
11
 
14
- from classiq.interface.debug_info.debug_info import FunctionDebugInfo
15
12
  from classiq.interface.generator.expressions.evaluated_expression import (
16
13
  EvaluatedExpression,
17
14
  )
18
15
  from classiq.interface.generator.expressions.expression import Expression
19
- from classiq.interface.generator.generated_circuit_data import OperationLevel
20
- from classiq.interface.model.classical_parameter_declaration import (
21
- ClassicalParameterDeclaration,
22
- )
23
- from classiq.interface.model.handle_binding import HandleBinding
24
16
  from classiq.interface.model.native_function_definition import NativeFunctionDefinition
25
- from classiq.interface.model.port_declaration import PortDeclaration
26
- from classiq.interface.model.quantum_function_call import ArgValue, QuantumFunctionCall
27
17
  from classiq.interface.model.quantum_function_declaration import (
28
18
  NamedParamsQuantumFunctionDeclaration,
29
- PositionalArg,
30
19
  )
31
20
  from classiq.interface.model.quantum_statement import QuantumOperation, QuantumStatement
32
- from classiq.interface.model.variable_declaration_statement import (
33
- VariableDeclarationStatement,
34
- )
35
21
 
36
22
  from classiq.model_expansions.capturing.propagated_var_stack import (
37
23
  PropagatedVarStack,
38
- validate_args_are_not_propagated,
39
24
  )
40
25
  from classiq.model_expansions.closure import Closure, FunctionClosure, GenerativeClosure
41
- from classiq.model_expansions.evaluators.argument_types import (
42
- add_information_from_output_arguments,
43
- )
44
- from classiq.model_expansions.evaluators.parameter_types import (
45
- evaluate_parameter_types_from_args,
46
- )
47
26
  from classiq.model_expansions.function_builder import (
48
27
  FunctionContext,
49
28
  OperationBuilder,
50
29
  OperationContext,
51
30
  )
52
- from classiq.model_expansions.generative_functions import emit_operands_as_declarative
53
- from classiq.model_expansions.scope import Evaluated, QuantumSymbol, Scope
31
+ from classiq.model_expansions.scope import Scope
54
32
  from classiq.model_expansions.sympy_conversion.sympy_to_python import (
55
33
  translate_sympy_quantum_expression,
56
34
  )
57
35
  from classiq.model_expansions.utils.counted_name_allocator import CountedNameAllocator
58
- from classiq.qmod.builtins.functions import allocate, free
59
36
  from classiq.qmod.quantum_function import GenerativeQFunc
60
37
 
61
38
  if TYPE_CHECKING:
@@ -116,168 +93,6 @@ class Emitter(Generic[QuantumStatementT]):
116
93
  def _counted_name_allocator(self) -> CountedNameAllocator:
117
94
  return self._interpreter._counted_name_allocator
118
95
 
119
- @staticmethod
120
- def _should_wrap(body: Sequence[QuantumStatement]) -> bool:
121
- # This protects shadowing of captured variables (i.e, bad user code) by wrapping the body in a function
122
- # I'm sure there are better ways to handle it, but this is the simplest way to do it for now
123
- return any(isinstance(stmt, VariableDeclarationStatement) for stmt in body)
124
-
125
- def _create_expanded_wrapping_function(
126
- self, name: str, body: Sequence[QuantumStatement]
127
- ) -> QuantumFunctionCall:
128
- wrapping_function = FunctionClosure.create(
129
- name=name, body=body, scope=Scope(parent=self._current_scope)
130
- )
131
- return self._create_quantum_function_call(wrapping_function, list())
132
-
133
- def _emit_quantum_function_call(
134
- self, function: FunctionClosure, args: list[ArgValue]
135
- ) -> QuantumFunctionCall:
136
- call = self._create_quantum_function_call(function, args)
137
- self._builder.emit_statement(call)
138
- return call
139
-
140
- def _create_quantum_function_call(
141
- self, function: FunctionClosure, args: list[ArgValue]
142
- ) -> QuantumFunctionCall:
143
- evaluated_args = [self._interpreter.evaluate(arg) for arg in args]
144
- new_declaration = self._prepare_fully_typed_declaration(
145
- function, evaluated_args
146
- )
147
- new_positional_arg_decls = new_declaration.positional_arg_declarations
148
- is_atomic = function.is_atomic
149
- new_function_name = function.name
150
- if not is_atomic: # perform monomorphization per interpreted parameters set
151
- self._add_params_to_scope(
152
- new_positional_arg_decls, evaluated_args, function
153
- )
154
- context = self._expand_operation(
155
- function.with_new_declaration(new_declaration)
156
- )
157
- function_context = cast(FunctionContext, context)
158
- closure_id = function_context.closure.closure_id
159
- function_def = self._expanded_functions.get(closure_id)
160
- if function_def is None:
161
- function_def = self._builder.create_definition(function_context)
162
- self._expanded_functions[closure_id] = function_def
163
- self._top_level_scope[function_def.name] = Evaluated(
164
- value=function_context.closure.with_new_declaration(function_def)
165
- )
166
- new_declaration = function_def
167
- new_function_name = function_def.name
168
- compilation_metadata = self._functions_compilation_metadata.get(
169
- function.name
170
- )
171
- if compilation_metadata is not None:
172
- self._expanded_functions_compilation_metadata[new_function_name] = (
173
- compilation_metadata
174
- )
175
-
176
- new_positional_args = self._get_new_positional_args(
177
- evaluated_args, is_atomic, new_positional_arg_decls
178
- )
179
- new_call = QuantumFunctionCall(
180
- function=new_function_name,
181
- positional_args=new_positional_args,
182
- )
183
- is_allocate_or_free = (
184
- new_call.func_name == allocate.func_decl.name
185
- or new_call.func_name == free.func_decl.name
186
- )
187
- parameters = {
188
- arg_decl.name: FunctionDebugInfo.param_controller(value=evaluated_arg.value)
189
- for arg_decl, evaluated_arg in zip(new_positional_arg_decls, evaluated_args)
190
- if isinstance(arg_decl, ClassicalParameterDeclaration)
191
- }
192
-
193
- port_to_passed_variable_map = {
194
- arg_decl.name: str(evaluated_arg.value.handle)
195
- for arg_decl, evaluated_arg in zip(new_positional_arg_decls, evaluated_args)
196
- if isinstance(arg_decl, PortDeclaration)
197
- }
198
- self._interpreter._model.debug_info[new_call.uuid] = FunctionDebugInfo(
199
- name=new_call.func_name,
200
- level=OperationLevel.QMOD_FUNCTION_CALL,
201
- parameters=parameters,
202
- is_allocate_or_free=is_allocate_or_free,
203
- port_to_passed_variable_map=port_to_passed_variable_map,
204
- )
205
- new_call.set_func_decl(new_declaration)
206
- return new_call
207
-
208
- @staticmethod
209
- def _add_params_to_scope(
210
- parameters: Sequence[PositionalArg],
211
- arguments: Sequence[Evaluated],
212
- closure: FunctionClosure,
213
- ) -> None:
214
- for parameter, argument in zip(parameters, arguments):
215
- if isinstance(argument.value, QuantumSymbol):
216
- assert isinstance(parameter, PortDeclaration)
217
- closure.scope[parameter.name] = Evaluated(
218
- QuantumSymbol(
219
- handle=HandleBinding(name=parameter.name),
220
- quantum_type=parameter.quantum_type,
221
- ),
222
- defining_function=closure,
223
- )
224
- else:
225
- closure.scope[parameter.name] = argument
226
-
227
- def _get_new_positional_args(
228
- self,
229
- evaluated_args: list[Evaluated],
230
- is_atomic: bool,
231
- new_positional_arg_decls: Sequence[PositionalArg],
232
- ) -> list[ArgValue]:
233
- evaluated_args = add_information_from_output_arguments(
234
- new_positional_arg_decls, evaluated_args
235
- )
236
- if is_atomic:
237
- return [
238
- emit_operands_as_declarative(self._interpreter, param, arg)
239
- for param, arg in zip(new_positional_arg_decls, evaluated_args)
240
- ]
241
-
242
- positional_args = [
243
- arg.emit() for arg in evaluated_args if isinstance(arg.value, QuantumSymbol)
244
- ]
245
-
246
- propagated_variables = self._propagated_var_stack.get_propagated_variables(
247
- flatten=True
248
- )
249
- validate_args_are_not_propagated(positional_args, propagated_variables)
250
- positional_args.extend(propagated_variables)
251
-
252
- return positional_args
253
-
254
- def _prepare_fully_typed_declaration(
255
- self, function: FunctionClosure, evaluated_args: list[Evaluated]
256
- ) -> NamedParamsQuantumFunctionDeclaration:
257
- """
258
- Given, for example,
259
- def my_func(x: int, q: QArray["x"], p: QArray[]) -> None:
260
- ...
261
- def main(...):
262
- ...
263
- allocate(5, s)
264
- my_func(3, r, s)
265
- The code below will evaluate x to be 3, q to be of size 3 and p to be of size 5.
266
- Note that it requires a scope for the parameter declaration space, which is
267
- different from the call scope. For example, the former uses r,s and the latter
268
- uses p, q.
269
- """
270
- with self._scope_guard(Scope(parent=self._current_scope)):
271
- # The signature scope is passed as a separate argument to avoid contaminating the statement execution scope
272
- return NamedParamsQuantumFunctionDeclaration(
273
- name=function.name,
274
- positional_arg_declarations=evaluate_parameter_types_from_args(
275
- function,
276
- function.signature_scope,
277
- evaluated_args,
278
- ),
279
- )
280
-
281
96
  def _register_generative_context(
282
97
  self,
283
98
  op: QuantumOperation,
@@ -1,79 +1,59 @@
1
1
  import ast
2
- from abc import abstractmethod
3
- from itertools import chain
4
- from typing import TYPE_CHECKING, TypeVar, Union
2
+ from typing import TYPE_CHECKING, Generic, TypeVar, Union
5
3
 
6
- from classiq.interface.exceptions import (
7
- ClassiqExpansionError,
8
- ClassiqInternalExpansionError,
9
- )
10
4
  from classiq.interface.generator.expressions.evaluated_expression import (
11
5
  EvaluatedExpression,
12
6
  )
13
7
  from classiq.interface.generator.expressions.expression import Expression
14
- from classiq.interface.generator.functions.type_name import TypeName
15
- from classiq.interface.generator.visitor import NodeType, Transformer
16
- from classiq.interface.model.bind_operation import BindOperation
8
+ from classiq.interface.generator.visitor import NodeType
17
9
  from classiq.interface.model.control import Control
18
- from classiq.interface.model.handle_binding import (
19
- FieldHandleBinding,
20
- HandleBinding,
21
- SlicedHandleBinding,
22
- SubscriptHandleBinding,
23
- )
24
10
  from classiq.interface.model.quantum_expressions.quantum_expression import (
25
11
  QuantumAssignmentOperation,
26
12
  QuantumExpressionOperation,
27
13
  )
28
14
  from classiq.interface.model.quantum_type import (
29
- QuantumBit,
30
- QuantumBitvector,
31
15
  QuantumNumeric,
32
- QuantumType,
33
- )
34
- from classiq.interface.model.variable_declaration_statement import (
35
- VariableDeclarationStatement,
36
16
  )
37
17
  from classiq.interface.model.within_apply_operation import WithinApply
38
18
 
39
- from classiq.model_expansions.quantum_operations.emitter import Emitter
19
+ from classiq.model_expansions.quantum_operations.call_emitter import CallEmitter
40
20
  from classiq.model_expansions.scope import QuantumSymbol
21
+ from classiq.model_expansions.transformers.var_splitter import (
22
+ SymbolParts,
23
+ VarSplitter,
24
+ )
41
25
  from classiq.model_expansions.visitors.variable_references import VarRefCollector
42
26
 
27
+ if TYPE_CHECKING:
28
+ from classiq.model_expansions.interpreter import Interpreter
29
+
43
30
  ExpressionOperationT = TypeVar("ExpressionOperationT", bound=QuantumExpressionOperation)
44
31
  AST_NODE = TypeVar("AST_NODE", bound=NodeType)
45
32
 
46
33
 
47
- class ExpressionOperationEmitter(Emitter[ExpressionOperationT]):
48
- @abstractmethod
49
- def emit(self, op: ExpressionOperationT, /) -> None:
50
- pass
34
+ class ExpressionOperationEmitter(
35
+ Generic[ExpressionOperationT], CallEmitter[ExpressionOperationT], VarSplitter
36
+ ):
37
+ def __init__(self, interpreter: "Interpreter") -> None:
38
+ CallEmitter.__init__(self, interpreter) # type:ignore[arg-type]
39
+ VarSplitter.__init__(self, interpreter._current_scope)
51
40
 
52
41
  def _emit_with_split(
53
42
  self,
54
43
  op: ExpressionOperationT,
55
44
  expression: Expression,
56
- symbols_to_split: dict[QuantumSymbol, set[HandleBinding]],
45
+ symbol_parts: SymbolParts,
57
46
  ) -> None:
58
- symbols_parts, bind_ops = self._get_bind_ops(symbols_to_split)
47
+ for var_decl in self.get_var_decls(symbol_parts):
48
+ self._interpreter.emit_statement(var_decl)
49
+ bind_ops = self.get_bind_ops(symbol_parts)
59
50
 
60
- for symbol_parts in symbols_parts:
61
- for symbol, symbol_part_var_name in symbol_parts:
62
- if symbol.handle.identifier not in self._current_scope:
63
- self._interpreter.emit_statement(
64
- VariableDeclarationStatement(
65
- name=symbol_part_var_name,
66
- quantum_type=symbol.quantum_type,
67
- )
68
- )
69
-
70
- symbol_mapping = {
71
- symbol.handle: (symbol_part_var_name, symbol.quantum_type)
72
- for symbol, symbol_part_var_name in chain.from_iterable(symbols_parts)
73
- }
74
- new_expression = self._update_op_expression(symbol_mapping, expression)
51
+ new_expression = self.rewrite(expression, symbol_parts)
52
+ new_expression._evaluated_expr = EvaluatedExpression(
53
+ value=self._interpreter.evaluate(new_expression).value
54
+ )
75
55
  new_op = op.model_copy(update=dict(expression=new_expression))
76
- new_op = self._get_updated_op_split_symbols(new_op, symbol_mapping)
56
+ new_op = self._get_updated_op_split_symbols(new_op, symbol_parts)
77
57
 
78
58
  self._interpreter.emit_statement(
79
59
  WithinApply(
@@ -86,125 +66,10 @@ class ExpressionOperationEmitter(Emitter[ExpressionOperationT]):
86
66
  def _get_updated_op_split_symbols(
87
67
  self,
88
68
  op: ExpressionOperationT,
89
- symbol_mapping: dict[HandleBinding, tuple[str, QuantumType]],
69
+ symbol_mapping: SymbolParts,
90
70
  ) -> ExpressionOperationT:
91
71
  return op
92
72
 
93
- def _update_op_expression(
94
- self,
95
- symbol_mapping: dict[HandleBinding, tuple[str, QuantumType]],
96
- expression: Expression,
97
- ) -> Expression:
98
- vrc = VarRefCollector(ignore_duplicated_handles=True)
99
- vrc.visit(ast.parse(expression.expr))
100
-
101
- new_expr_str = expression.expr
102
- for handle in vrc.var_handles:
103
- collapsed_handle = handle.collapse()
104
- if collapsed_handle in symbol_mapping:
105
- new_expr_str = new_expr_str.replace(
106
- str(handle), symbol_mapping[collapsed_handle][0]
107
- )
108
- self._check_all_handles_were_replaced(new_expr_str)
109
-
110
- new_expr = Expression(expr=new_expr_str)
111
- new_expr._evaluated_expr = EvaluatedExpression(
112
- value=self._interpreter.evaluate(new_expr).value
113
- )
114
- return new_expr
115
-
116
- def _check_all_handles_were_replaced(self, new_expr_str: str) -> None:
117
- vrc = VarRefCollector(ignore_duplicated_handles=True)
118
- vrc.visit(ast.parse(new_expr_str))
119
- for handle in self._get_handles(vrc):
120
- if isinstance(
121
- handle,
122
- (SubscriptHandleBinding, SlicedHandleBinding, FieldHandleBinding),
123
- ):
124
- raise ClassiqInternalExpansionError(f"Did not replace handle {handle}")
125
-
126
- def _get_bind_ops(
127
- self,
128
- symbols_to_split: dict[QuantumSymbol, set[HandleBinding]],
129
- ) -> tuple[list[list[tuple[QuantumSymbol, str]]], list[BindOperation]]:
130
- bind_ops = []
131
- symbols_parts = []
132
- for symbol, target_parts in symbols_to_split.items():
133
- symbol_parts = self._get_symbol_parts(symbol, target_parts)
134
- symbols_parts.append(symbol_parts)
135
- bind_ops.append(
136
- BindOperation(
137
- in_handles=[symbol.handle],
138
- out_handles=[
139
- HandleBinding(name=symbol_part_var_name)
140
- for _, symbol_part_var_name in symbol_parts
141
- ],
142
- )
143
- )
144
- return symbols_parts, bind_ops
145
-
146
- def _get_symbol_parts(
147
- self, symbol: QuantumSymbol, target_parts: set[HandleBinding]
148
- ) -> list[tuple[QuantumSymbol, str]]:
149
- quantum_type = symbol.quantum_type
150
-
151
- if all(
152
- symbol.handle == target_part or symbol.handle not in target_part.prefixes()
153
- for target_part in target_parts
154
- ) or isinstance(quantum_type, (QuantumBit, QuantumNumeric)):
155
- return [
156
- (
157
- symbol,
158
- self._counted_name_allocator.allocate(symbol.handle.identifier),
159
- )
160
- ]
161
-
162
- if isinstance(quantum_type, QuantumBitvector):
163
- if not quantum_type.has_length:
164
- raise ClassiqExpansionError(
165
- f"Could not determine the length of quantum array "
166
- f"{symbol.handle}."
167
- )
168
- return list(
169
- chain.from_iterable(
170
- self._get_symbol_parts(symbol[idx], target_parts)
171
- for idx in range(quantum_type.length_value)
172
- )
173
- )
174
-
175
- if TYPE_CHECKING:
176
- assert isinstance(quantum_type, TypeName)
177
-
178
- return list(
179
- chain.from_iterable(
180
- self._get_symbol_parts(field_symbol, target_parts)
181
- for field_symbol in symbol.fields.values()
182
- )
183
- )
184
-
185
- def _get_symbols_to_split(
186
- self, expression: Expression
187
- ) -> dict[QuantumSymbol, set[HandleBinding]]:
188
- vrc = VarRefCollector(ignore_duplicated_handles=True)
189
- vrc.visit(ast.parse(expression.expr))
190
- symbol_names_to_split = dict.fromkeys(
191
- handle.name
192
- for handle in self._get_handles(vrc)
193
- if isinstance(handle, (SubscriptHandleBinding, FieldHandleBinding))
194
- )
195
- return {
196
- symbol: {
197
- handle.collapse()
198
- for handle in vrc.var_handles
199
- if handle.name == symbol.handle.name
200
- }
201
- for symbol_name in symbol_names_to_split
202
- if isinstance(
203
- symbol := self._current_scope[symbol_name].value,
204
- QuantumSymbol,
205
- )
206
- }
207
-
208
73
  def _evaluate_op_expression(self, op: ExpressionOperationT) -> Expression:
209
74
  return self._evaluate_expression(op.expression)
210
75
 
@@ -248,31 +113,3 @@ class ExpressionOperationEmitter(Emitter[ExpressionOperationT]):
248
113
  isinstance(op.result_type, QuantumNumeric)
249
114
  and (op.result_type.sign_value or op.result_type.fraction_digits_value > 0)
250
115
  )
251
-
252
- def _get_handles(self, collector: VarRefCollector) -> list[HandleBinding]:
253
- return [
254
- handle
255
- for handle in collector.var_handles
256
- if isinstance(self._interpreter.evaluate(handle.name).value, QuantumSymbol)
257
- ]
258
-
259
- def _rewrite(
260
- self,
261
- subject: AST_NODE,
262
- symbol_mapping: dict[HandleBinding, tuple[str, QuantumType]],
263
- ) -> AST_NODE:
264
- class ReplaceSplitVars(Transformer):
265
- @staticmethod
266
- def visit_HandleBinding(handle: HandleBinding) -> HandleBinding:
267
- handle = handle.collapse()
268
- for handle_to_replace, replacement in symbol_mapping.items():
269
- handle = handle.replace_prefix(
270
- handle_to_replace, HandleBinding(name=replacement[0])
271
- )
272
- return handle
273
-
274
- @staticmethod
275
- def visit_Expression(expr: Expression) -> Expression:
276
- return self._update_op_expression(symbol_mapping, expr)
277
-
278
- return ReplaceSplitVars().visit(subject)
@@ -31,7 +31,7 @@ from classiq.model_expansions.evaluators.parameter_types import (
31
31
  from classiq.model_expansions.evaluators.quantum_type_utils import (
32
32
  validate_inplace_binary_op_vars,
33
33
  )
34
- from classiq.model_expansions.quantum_operations.emitter import Emitter
34
+ from classiq.model_expansions.quantum_operations.call_emitter import CallEmitter
35
35
  from classiq.model_expansions.scope import QuantumSymbol, Scope
36
36
  from classiq.qmod.builtins.functions import (
37
37
  CX,
@@ -59,7 +59,7 @@ def _binary_function_declaration(
59
59
  }[constant][op]
60
60
 
61
61
 
62
- class InplaceBinaryOperationEmitter(Emitter[InplaceBinaryOperation]):
62
+ class InplaceBinaryOperationEmitter(CallEmitter[InplaceBinaryOperation]):
63
63
  def emit(self, op: InplaceBinaryOperation, /) -> None:
64
64
  if isinstance(op.value, Expression):
65
65
  self._emit_constant_operation(op)
@@ -4,11 +4,11 @@ from classiq.interface.generator.functions.builtins.internal_operators import (
4
4
  from classiq.interface.model.invert import Invert
5
5
 
6
6
  from classiq.model_expansions.closure import Closure
7
- from classiq.model_expansions.quantum_operations.emitter import Emitter
7
+ from classiq.model_expansions.quantum_operations.call_emitter import CallEmitter
8
8
  from classiq.model_expansions.scope import Scope
9
9
 
10
10
 
11
- class InvertEmitter(Emitter[Invert]):
11
+ class InvertEmitter(CallEmitter[Invert]):
12
12
  def emit(self, invert: Invert, /) -> None:
13
13
  with self._propagated_var_stack.capture_variables(invert):
14
14
  self._emit_propagated(invert)
@@ -41,7 +41,9 @@ class PhaseEmitter(ExpressionOperationEmitter[PhaseOperation]):
41
41
  def emit(self, phase_op: PhaseOperation, /) -> None:
42
42
  phase_expression = self._evaluate_op_expression(phase_op)
43
43
  phase_op = phase_op.model_copy(update=dict(expression=phase_expression))
44
- arrays_with_subscript = self._get_symbols_to_split(phase_op.expression)
44
+ arrays_with_subscript = self.split_symbols(
45
+ phase_op.expression, self._counted_name_allocator.allocate
46
+ )
45
47
  if len(arrays_with_subscript) > 0:
46
48
  self._emit_with_split(phase_op, phase_op.expression, arrays_with_subscript)
47
49
  return
@@ -13,11 +13,11 @@ from classiq.interface.generator.functions.builtins.internal_operators import (
13
13
  from classiq.interface.model.power import Power
14
14
 
15
15
  from classiq.model_expansions.closure import Closure
16
- from classiq.model_expansions.quantum_operations.emitter import Emitter
16
+ from classiq.model_expansions.quantum_operations.call_emitter import CallEmitter
17
17
  from classiq.model_expansions.scope import Scope
18
18
 
19
19
 
20
- class PowerEmitter(Emitter[Power]):
20
+ class PowerEmitter(CallEmitter[Power]):
21
21
  _power_value: Union[int, sympy.Basic]
22
22
  _power_expr: Expression
23
23
 
@@ -20,10 +20,7 @@ from classiq.interface.model.quantum_expressions.quantum_expression import (
20
20
  QuantumAssignmentOperation,
21
21
  )
22
22
  from classiq.interface.model.quantum_function_call import QuantumFunctionCall
23
- from classiq.interface.model.quantum_type import (
24
- QuantumNumeric,
25
- QuantumType,
26
- )
23
+ from classiq.interface.model.quantum_type import QuantumNumeric
27
24
  from classiq.interface.model.variable_declaration_statement import (
28
25
  VariableDeclarationStatement,
29
26
  )
@@ -35,6 +32,7 @@ from classiq.model_expansions.quantum_operations.expression_operation import (
35
32
  ExpressionOperationEmitter,
36
33
  )
37
34
  from classiq.model_expansions.scope import QuantumSymbol
35
+ from classiq.model_expansions.transformers.var_splitter import SymbolParts
38
36
  from classiq.model_expansions.visitors.boolean_expression_transformers import (
39
37
  BooleanExpressionFuncLibAdapter,
40
38
  BooleanExpressionOptimizer,
@@ -70,7 +68,9 @@ class QuantumAssignmentOperationEmitter(
70
68
  new_expression = self._evaluate_op_expression(op)
71
69
  if self._skip_assignment(op, new_expression.expr):
72
70
  return
73
- arrays_with_subscript = self._get_symbols_to_split(new_expression)
71
+ arrays_with_subscript = self.split_symbols(
72
+ new_expression, self._counted_name_allocator.allocate
73
+ )
74
74
  if len(arrays_with_subscript) > 0:
75
75
  self._emit_with_split(op, new_expression, arrays_with_subscript)
76
76
  return
@@ -230,12 +230,10 @@ class QuantumAssignmentOperationEmitter(
230
230
  return True
231
231
 
232
232
  def _get_updated_op_split_symbols(
233
- self,
234
- op: QuantumAssignmentOperation,
235
- symbol_mapping: dict[HandleBinding, tuple[str, QuantumType]],
233
+ self, op: QuantumAssignmentOperation, symbol_parts: SymbolParts
236
234
  ) -> QuantumAssignmentOperation:
237
235
  return op.model_copy(
238
- update=dict(result_var=self._rewrite(op.result_var, symbol_mapping))
236
+ update=dict(result_var=self.rewrite(op.result_var, symbol_parts))
239
237
  )
240
238
 
241
239
 
@@ -3,14 +3,14 @@ from typing import TYPE_CHECKING
3
3
  from classiq.interface.model.quantum_function_call import QuantumFunctionCall
4
4
 
5
5
  from classiq.model_expansions.closure import FunctionClosure
6
- from classiq.model_expansions.quantum_operations.emitter import Emitter
6
+ from classiq.model_expansions.quantum_operations.call_emitter import CallEmitter
7
7
  from classiq.qmod.semantics.error_manager import ErrorManager
8
8
 
9
9
  if TYPE_CHECKING:
10
10
  from classiq.model_expansions.interpreter import Interpreter
11
11
 
12
12
 
13
- class QuantumFunctionCallEmitter(Emitter[QuantumFunctionCall]):
13
+ class QuantumFunctionCallEmitter(CallEmitter[QuantumFunctionCall]):
14
14
  def __init__(self, interpreter: "Interpreter") -> None:
15
15
  super().__init__(interpreter)
16
16
  self._model = self._interpreter._model
@@ -10,12 +10,12 @@ from classiq.interface.model.classical_parameter_declaration import (
10
10
  from classiq.interface.model.repeat import Repeat
11
11
 
12
12
  from classiq.model_expansions.closure import FunctionClosure, GenerativeFunctionClosure
13
- from classiq.model_expansions.quantum_operations.emitter import Emitter
13
+ from classiq.model_expansions.quantum_operations.call_emitter import CallEmitter
14
14
  from classiq.model_expansions.scope import Scope
15
15
  from classiq.qmod.quantum_function import GenerativeQFunc
16
16
 
17
17
 
18
- class RepeatEmitter(Emitter[Repeat]):
18
+ class RepeatEmitter(CallEmitter[Repeat]):
19
19
  def emit(self, repeat: Repeat, /) -> None:
20
20
  count = self._interpreter.evaluate(repeat.count).as_type(int)
21
21
  if count < 0:
File without changes