classiq 0.47.0__py3-none-any.whl → 0.48.1__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 (56) hide show
  1. classiq/applications/combinatorial_helpers/pauli_helpers/pauli_utils.py +2 -7
  2. classiq/applications/grover/grover_model_constructor.py +2 -1
  3. classiq/execution/execution_session.py +40 -9
  4. classiq/execution/jobs.py +18 -6
  5. classiq/interface/_version.py +1 -1
  6. classiq/interface/execution/primitives.py +9 -1
  7. classiq/interface/executor/iqae_result.py +3 -3
  8. classiq/interface/executor/result.py +3 -1
  9. classiq/interface/generator/expressions/expression.py +8 -0
  10. classiq/interface/generator/functions/type_name.py +1 -3
  11. classiq/interface/generator/synthesis_metadata/synthesis_execution_data.py +17 -3
  12. classiq/interface/ide/visual_model.py +3 -4
  13. classiq/interface/model/bind_operation.py +0 -3
  14. classiq/interface/model/port_declaration.py +1 -12
  15. classiq/interface/model/quantum_expressions/arithmetic_operation.py +38 -6
  16. classiq/interface/model/quantum_lambda_function.py +4 -1
  17. classiq/interface/model/quantum_statement.py +16 -1
  18. classiq/interface/model/quantum_variable_declaration.py +0 -22
  19. classiq/interface/server/global_versions.py +4 -4
  20. classiq/model_expansions/capturing/propagated_var_stack.py +5 -2
  21. classiq/model_expansions/closure.py +7 -2
  22. classiq/model_expansions/evaluators/quantum_type_utils.py +0 -7
  23. classiq/model_expansions/generative_functions.py +146 -28
  24. classiq/model_expansions/interpreter.py +11 -5
  25. classiq/model_expansions/quantum_operations/classicalif.py +27 -10
  26. classiq/model_expansions/quantum_operations/control.py +22 -15
  27. classiq/model_expansions/quantum_operations/emitter.py +60 -5
  28. classiq/model_expansions/quantum_operations/expression_operation.py +25 -16
  29. classiq/model_expansions/quantum_operations/inplace_binary_operation.py +163 -95
  30. classiq/model_expansions/quantum_operations/invert.py +12 -6
  31. classiq/model_expansions/quantum_operations/phase.py +15 -3
  32. classiq/model_expansions/quantum_operations/power.py +9 -8
  33. classiq/model_expansions/quantum_operations/quantum_assignment_operation.py +20 -5
  34. classiq/model_expansions/quantum_operations/quantum_function_call.py +1 -1
  35. classiq/model_expansions/quantum_operations/repeat.py +32 -13
  36. classiq/model_expansions/quantum_operations/within_apply.py +19 -6
  37. classiq/model_expansions/scope.py +16 -5
  38. classiq/model_expansions/scope_initialization.py +11 -1
  39. classiq/model_expansions/sympy_conversion/expression_to_sympy.py +23 -1
  40. classiq/model_expansions/visitors/variable_references.py +11 -7
  41. classiq/qmod/builtins/__init__.py +10 -0
  42. classiq/qmod/builtins/constants.py +10 -0
  43. classiq/qmod/builtins/functions/state_preparation.py +4 -1
  44. classiq/qmod/builtins/operations.py +43 -163
  45. classiq/qmod/create_model_function.py +1 -1
  46. classiq/qmod/generative.py +14 -5
  47. classiq/qmod/native/pretty_printer.py +9 -5
  48. classiq/qmod/pretty_print/pretty_printer.py +8 -4
  49. classiq/qmod/qmod_constant.py +28 -18
  50. classiq/qmod/qmod_variable.py +43 -23
  51. classiq/qmod/quantum_expandable.py +14 -1
  52. classiq/qmod/semantics/static_semantics_visitor.py +10 -0
  53. classiq/qmod/semantics/validation/constants_validation.py +16 -0
  54. {classiq-0.47.0.dist-info → classiq-0.48.1.dist-info}/METADATA +3 -1
  55. {classiq-0.47.0.dist-info → classiq-0.48.1.dist-info}/RECORD +56 -54
  56. {classiq-0.47.0.dist-info → classiq-0.48.1.dist-info}/WHEEL +0 -0
@@ -1,51 +1,82 @@
1
- from typing import TYPE_CHECKING, Any, List
1
+ from typing import TYPE_CHECKING, Any, List, Mapping
2
2
 
3
+ from classiq.interface.exceptions import ClassiqInternalExpansionError
3
4
  from classiq.interface.generator.expressions.qmod_struct_instance import (
4
5
  QmodStructInstance,
5
6
  )
6
7
  from classiq.interface.generator.functions.type_name import Struct
8
+ from classiq.interface.generator.visitor import Visitor
7
9
  from classiq.interface.helpers.pydantic_model_helpers import nameables_to_dict
8
10
  from classiq.interface.model.native_function_definition import NativeFunctionDefinition
9
11
  from classiq.interface.model.port_declaration import PortDeclaration
12
+ from classiq.interface.model.quantum_function_call import ArgValue, QuantumFunctionCall
10
13
  from classiq.interface.model.quantum_function_declaration import (
11
14
  PositionalArg,
12
15
  QuantumFunctionDeclaration,
13
16
  QuantumOperandDeclaration,
14
17
  )
18
+ from classiq.interface.model.quantum_lambda_function import (
19
+ QuantumCallable,
20
+ QuantumLambdaFunction,
21
+ )
15
22
  from classiq.interface.model.quantum_statement import QuantumStatement
16
23
 
17
- from classiq.model_expansions.closure import FunctionClosure, GenerativeFunctionClosure
24
+ from classiq.model_expansions.closure import (
25
+ FunctionClosure,
26
+ GenerativeClosure,
27
+ GenerativeFunctionClosure,
28
+ )
18
29
  from classiq.model_expansions.scope import Evaluated, QuantumSymbol
19
30
  from classiq.qmod.generative import generative_mode_context, set_frontend_interpreter
20
31
  from classiq.qmod.model_state_container import QMODULE
21
32
  from classiq.qmod.qmod_parameter import CParamStruct
22
- from classiq.qmod.qmod_variable import get_qvar
33
+ from classiq.qmod.qmod_variable import QNum, _create_qvar_for_qtype
23
34
  from classiq.qmod.quantum_callable import QCallable
24
- from classiq.qmod.quantum_expandable import QExpandable, QTerminalCallable
35
+ from classiq.qmod.quantum_expandable import (
36
+ QExpandable,
37
+ QLambdaFunction,
38
+ QTerminalCallable,
39
+ )
25
40
  from classiq.qmod.quantum_function import QFunc
26
41
  from classiq.qmod.semantics.static_semantics_visitor import resolve_function_calls
42
+ from classiq.qmod.symbolic_expr import SymbolicExpr
27
43
 
28
44
  if TYPE_CHECKING:
29
45
  from classiq.model_expansions.interpreter import Interpreter
30
46
 
31
47
 
48
+ class LenList(list):
49
+ @property
50
+ def len(self) -> int:
51
+ return len(self)
52
+
53
+ def __getitem__(self, item: Any) -> Any:
54
+ if isinstance(item, QNum):
55
+ return SymbolicExpr(f"{self}[{item}]", True)
56
+ return super().__getitem__(item)
57
+
58
+ @classmethod
59
+ def wrap(cls, obj: Any) -> Any:
60
+ if not isinstance(obj, list):
61
+ return obj
62
+ return LenList([cls.wrap(item) for item in obj])
63
+
64
+
32
65
  def translate_ast_arg_to_python_qmod(param: PositionalArg, evaluated: Evaluated) -> Any:
33
66
  if isinstance(param, PortDeclaration):
34
67
  quantum_symbol = evaluated.as_type(QuantumSymbol)
35
- return get_qvar(quantum_symbol.quantum_type, quantum_symbol.handle)
68
+ return _create_qvar_for_qtype(
69
+ quantum_symbol.quantum_type, quantum_symbol.handle
70
+ )
36
71
  if isinstance(param, QuantumOperandDeclaration):
37
72
  if param.is_list:
38
- func_list: List[FunctionClosure] = evaluated.as_type(list)
39
- return [
40
- QTerminalCallable(
41
- QuantumFunctionDeclaration(
42
- name=param.name,
43
- positional_arg_declarations=param.positional_arg_declarations,
44
- ),
45
- index_=idx,
46
- )
47
- for idx, func in enumerate(func_list)
48
- ]
73
+ return QTerminalCallable(
74
+ QuantumOperandDeclaration(
75
+ name=param.name,
76
+ positional_arg_declarations=param.positional_arg_declarations,
77
+ is_list=True,
78
+ ),
79
+ )
49
80
  else:
50
81
  func = evaluated.as_type(FunctionClosure)
51
82
  return QTerminalCallable(
@@ -61,7 +92,7 @@ def translate_ast_arg_to_python_qmod(param: PositionalArg, evaluated: Evaluated)
61
92
  struct_type=Struct(name=classical_value.struct_declaration.name),
62
93
  qmodule=QMODULE,
63
94
  )
64
- return classical_value
95
+ return LenList.wrap(classical_value)
65
96
 
66
97
 
67
98
  class _InterpreterExpandable(QFunc):
@@ -70,23 +101,32 @@ class _InterpreterExpandable(QFunc):
70
101
  self._interpreter = interpreter
71
102
 
72
103
  def append_statement_to_body(self, stmt: QuantumStatement) -> None:
73
- current_function = self._interpreter._builder.current_function
104
+ current_operation = self._interpreter._builder._operations[-1]
74
105
  dummy_function = NativeFunctionDefinition(
75
- name=current_function.name,
76
- positional_arg_declarations=current_function.positional_arg_declarations,
106
+ name=current_operation.name,
107
+ positional_arg_declarations=current_operation.positional_arg_declarations,
77
108
  body=self._interpreter._builder._current_statements + [stmt],
78
109
  )
79
- resolve_function_calls(
80
- dummy_function,
81
- nameables_to_dict(self._interpreter._get_function_declarations()),
82
- )
110
+ resolve_function_calls(dummy_function, self._get_function_declarations())
83
111
  stmt = dummy_function.body[-1]
84
- self._interpreter.emit_statement(stmt)
112
+ with generative_mode_context(False):
113
+ self._interpreter.emit_statement(stmt)
114
+
115
+ def _get_function_declarations(self) -> Mapping[str, QuantumFunctionDeclaration]:
116
+ return {
117
+ name: QuantumFunctionDeclaration(
118
+ name=name,
119
+ positional_arg_declarations=evaluated.value.positional_arg_declarations,
120
+ )
121
+ for name, evaluated in self._interpreter._current_scope.items()
122
+ if isinstance(evaluated, Evaluated)
123
+ and isinstance(evaluated.value, FunctionClosure)
124
+ } | nameables_to_dict(self._interpreter._get_function_declarations())
85
125
 
86
126
 
87
127
  def emit_generative_statements(
88
128
  interpreter: "Interpreter",
89
- operation: GenerativeFunctionClosure,
129
+ operation: GenerativeClosure,
90
130
  args: List[Evaluated],
91
131
  ) -> None:
92
132
  python_qmod_args = [
@@ -97,5 +137,83 @@ def emit_generative_statements(
97
137
  QExpandable.STACK.append(interpreter_expandable)
98
138
  QCallable.CURRENT_EXPANDABLE = interpreter_expandable
99
139
  set_frontend_interpreter(interpreter)
100
- with interpreter._builder.block_context("body"), generative_mode_context(True):
101
- operation.generative_function._py_callable(*python_qmod_args)
140
+ for block_name, generative_function in operation.generative_blocks.items():
141
+ with interpreter._builder.block_context(block_name), generative_mode_context(
142
+ True
143
+ ):
144
+ generative_function._py_callable(*python_qmod_args)
145
+
146
+
147
+ def emit_operands_as_declarative(
148
+ interpreter: "Interpreter", param: PositionalArg, arg: Evaluated
149
+ ) -> ArgValue:
150
+ if not isinstance(param, QuantumOperandDeclaration):
151
+ return arg.emit()
152
+ value = arg.value
153
+ if isinstance(value, list):
154
+ return [
155
+ _expand_operand_as_declarative(interpreter, param, item) for item in value
156
+ ]
157
+ if isinstance(value, GenerativeFunctionClosure):
158
+ return _expand_operand_as_declarative(interpreter, param, value)
159
+ if isinstance(value, FunctionClosure):
160
+ if value.is_lambda:
161
+ raise ClassiqInternalExpansionError
162
+ _register_declarative_function(interpreter, value.name)
163
+ return value.name
164
+ raise ClassiqInternalExpansionError
165
+
166
+
167
+ def _expand_operand_as_declarative(
168
+ interpreter: "Interpreter",
169
+ param: QuantumOperandDeclaration,
170
+ arg: GenerativeFunctionClosure,
171
+ ) -> QuantumCallable:
172
+ if not arg.is_lambda:
173
+ _register_declarative_function(interpreter, arg.name)
174
+ return arg.name
175
+ val = QLambdaFunction(param, arg.generative_blocks["body"]._py_callable)
176
+ with generative_mode_context(False):
177
+ val.expand()
178
+ _DecFuncVisitor(interpreter).visit(val.body)
179
+ qlambda = QuantumLambdaFunction(
180
+ pos_rename_params=val.infer_rename_params(),
181
+ body=val.body,
182
+ )
183
+ qlambda.set_op_decl(param)
184
+ return qlambda
185
+
186
+
187
+ def _register_declarative_function(interpreter: "Interpreter", func_name: str) -> None:
188
+ if func_name in nameables_to_dict(interpreter._expanded_functions):
189
+ return
190
+
191
+ for user_gen_func in interpreter._generative_functions:
192
+ if user_gen_func.func_decl.name == func_name:
193
+ break
194
+ else:
195
+ return
196
+
197
+ with generative_mode_context(False):
198
+ dec_func = QFunc(user_gen_func._py_callable)
199
+ dec_func.expand()
200
+ dec_func_def = QMODULE.native_defs[func_name]
201
+ interpreter._expanded_functions.append(dec_func_def)
202
+ _DecFuncVisitor(interpreter).visit(dec_func_def)
203
+
204
+
205
+ class _DecFuncVisitor(Visitor):
206
+ def __init__(self, interpreter: "Interpreter"):
207
+ self._interpreter = interpreter
208
+
209
+ def visit_QuantumFunctionCall(self, call: QuantumFunctionCall) -> None:
210
+ _register_declarative_function(self._interpreter, call.func_name)
211
+ for arg in call.positional_args:
212
+ if isinstance(arg, str):
213
+ arg = [arg]
214
+ if isinstance(arg, list):
215
+ for possible_func_name in arg:
216
+ if isinstance(possible_func_name, str):
217
+ _register_declarative_function(
218
+ self._interpreter, possible_func_name
219
+ )
@@ -49,6 +49,7 @@ from classiq.model_expansions.capturing.propagated_var_stack import PropagatedVa
49
49
  from classiq.model_expansions.closure import (
50
50
  Closure,
51
51
  FunctionClosure,
52
+ GenerativeClosure,
52
53
  GenerativeFunctionClosure,
53
54
  )
54
55
  from classiq.model_expansions.debug_flag import debug_mode
@@ -84,7 +85,6 @@ from classiq.model_expansions.scope_initialization import (
84
85
  )
85
86
  from classiq.model_expansions.utils.counted_name_allocator import CountedNameAllocator
86
87
  from classiq.qmod.builtins.functions import permute
87
- from classiq.qmod.generative import is_generative_mode
88
88
  from classiq.qmod.quantum_function import GenerativeQFunc
89
89
  from classiq.qmod.semantics.error_manager import ErrorManager
90
90
 
@@ -97,8 +97,12 @@ STATEMENT_TYPES_FOR_SOURCE_REFERENCE_PROPAGATION: Tuple[Type[QuantumStatement],
97
97
 
98
98
  class Interpreter:
99
99
  def __init__(
100
- self, model: Model, generative_functions: Optional[List[GenerativeQFunc]] = None
100
+ self,
101
+ model: Model,
102
+ generative_functions: Optional[List[GenerativeQFunc]] = None,
103
+ is_frontend: bool = False,
101
104
  ) -> None:
105
+ self._is_frontend = is_frontend
102
106
  self._model = model
103
107
  self._current_scope = Scope()
104
108
  self._builder = OperationBuilder()
@@ -202,10 +206,12 @@ class Interpreter:
202
206
 
203
207
  closure_class: Type[FunctionClosure]
204
208
  extra_args: dict[str, Any]
205
- if is_generative_mode():
209
+ if function.is_generative():
206
210
  closure_class = GenerativeFunctionClosure
207
211
  extra_args = {
208
- "generative_function": GenerativeQFunc(function.py_callable, func_decl)
212
+ "generative_blocks": {
213
+ "body": GenerativeQFunc(function.py_callable, func_decl),
214
+ }
209
215
  }
210
216
  else:
211
217
  closure_class = FunctionClosure
@@ -337,7 +343,7 @@ class Interpreter:
337
343
  # special expansion since permute is generative
338
344
  with self._scope_guard(operation.scope):
339
345
  self._expand_permute()
340
- elif isinstance(operation, GenerativeFunctionClosure):
346
+ elif isinstance(operation, GenerativeClosure):
341
347
  with self._scope_guard(operation.scope):
342
348
  args = [
343
349
  self.evaluate(param.name)
@@ -1,15 +1,15 @@
1
- from typing import List
1
+ from typing 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
5
- from classiq.interface.model.statement_block import ConcreteQuantumStatement
5
+ from classiq.interface.model.quantum_statement import QuantumStatement
6
6
 
7
7
  from classiq.model_expansions.closure import FunctionClosure
8
8
  from classiq.model_expansions.quantum_operations.emitter import Emitter
9
9
  from classiq.model_expansions.scope import Scope
10
10
 
11
11
 
12
- def _is_all_identity_calls(body: List[ConcreteQuantumStatement]) -> bool:
12
+ def _is_all_identity_calls(body: Sequence[QuantumStatement]) -> bool:
13
13
  return all(
14
14
  isinstance(stmt, QuantumFunctionCall) and stmt.func_name.lower() == "identity"
15
15
  for stmt in body
@@ -18,22 +18,39 @@ def _is_all_identity_calls(body: List[ConcreteQuantumStatement]) -> bool:
18
18
 
19
19
  class ClassicalIfEmitter(Emitter[ClassicalIf]):
20
20
  def emit(self, classical_if: ClassicalIf, /) -> None:
21
+ with self._propagated_var_stack.capture_variables(classical_if):
22
+ self._emit_propagated(classical_if)
23
+
24
+ def _emit_propagated(self, classical_if: ClassicalIf) -> None:
21
25
  condition = self._interpreter.evaluate(classical_if.condition).as_type(bool)
22
- body: List[ConcreteQuantumStatement] = (
23
- classical_if.then if condition else classical_if.else_
24
- )
26
+ op_name = "then" if condition else "else"
27
+ is_generative = classical_if.is_generative()
28
+
29
+ body: Sequence[QuantumStatement]
30
+ if is_generative:
31
+ if not classical_if.has_generative_block(op_name):
32
+ return
33
+ context = self._register_generative_context(classical_if, op_name, op_name)
34
+ context.blocks["body"] = context.blocks[op_name]
35
+ context.blocks.pop(op_name)
36
+ body = context.statements("body")
37
+ else:
38
+ body = classical_if.then if condition else classical_if.else_
39
+
25
40
  if _is_all_identity_calls(body):
26
41
  return
27
42
 
28
43
  if not self._should_wrap(body):
29
44
  for stmt in body:
30
- self._interpreter.emit_statement(stmt)
45
+ if is_generative:
46
+ self._interpreter._builder.emit_statement(stmt)
47
+ else:
48
+ self._interpreter.emit_statement(stmt)
31
49
  return
32
50
 
33
51
  then_else_func = FunctionClosure.create(
34
- name="then" if condition else "else",
52
+ name=op_name,
35
53
  body=body,
36
54
  scope=Scope(parent=self._current_scope),
37
55
  )
38
- with self._propagated_var_stack.capture_variables(classical_if):
39
- self._emit_quantum_function_call(then_else_func, list())
56
+ self._emit_quantum_function_call(then_else_func, list())
@@ -21,6 +21,7 @@ from classiq.interface.model.control import Control
21
21
  from classiq.interface.model.handle_binding import HANDLE_ID_SEPARATOR, HandleBinding
22
22
  from classiq.interface.model.quantum_expressions.arithmetic_operation import (
23
23
  ArithmeticOperation,
24
+ ArithmeticOperationKind,
24
25
  )
25
26
  from classiq.interface.model.quantum_function_call import QuantumFunctionCall
26
27
  from classiq.interface.model.quantum_type import QuantumBit, QuantumBitvector
@@ -69,6 +70,14 @@ class ControlEmitter(ExpressionOperationEmitter[Control]):
69
70
  def _emit_canonical_control(self, control: Control) -> None:
70
71
  # canonical means control(q, body) where q is a single quantum variable
71
72
  control = self._evaluate_types_in_expression(control, control.expression)
73
+ with self._propagated_var_stack.capture_variables(control):
74
+ self._emit_propagated(control)
75
+
76
+ def _emit_propagated(self, control: Control) -> None:
77
+ if control.is_generative():
78
+ context = self._register_generative_context(control, CONTROL_OPERATOR_NAME)
79
+ control = control.copy(update={"body": context.statements("body")})
80
+
72
81
  if self._should_wrap_control(control):
73
82
  self._emit_wrapped(control)
74
83
  return
@@ -90,26 +99,24 @@ class ControlEmitter(ExpressionOperationEmitter[Control]):
90
99
  blocks=dict(body=control.body),
91
100
  scope=Scope(parent=self._current_scope),
92
101
  )
93
- with self._propagated_var_stack.capture_variables(control):
94
- context = self._expand_operation(control_operation)
95
- validate_args_are_not_propagated(
96
- control.var_handles,
97
- self._propagated_var_stack.get_propagated_variables(),
98
- )
102
+ context = self._expand_operation(control_operation)
103
+ validate_args_are_not_propagated(
104
+ control.var_handles,
105
+ self._propagated_var_stack.get_propagated_variables(),
106
+ )
99
107
  self._update_control_state(control)
100
108
  self._builder.emit_statement(
101
109
  control.copy(update=dict(body=context.statements("body")))
102
110
  )
103
111
 
104
112
  def _emit_wrapped(self, control: Control) -> None:
105
- with self._propagated_var_stack.capture_variables(control):
106
- wrapping_function = self._create_expanded_wrapping_function(
107
- CONTROL_OPERATOR_NAME, control.body
108
- )
109
- validate_args_are_not_propagated(
110
- control.var_handles,
111
- self._propagated_var_stack.get_propagated_variables(),
112
- )
113
+ wrapping_function = self._create_expanded_wrapping_function(
114
+ CONTROL_OPERATOR_NAME, control.body
115
+ )
116
+ validate_args_are_not_propagated(
117
+ control.var_handles,
118
+ self._propagated_var_stack.get_propagated_variables(),
119
+ )
113
120
  self._update_control_state(control)
114
121
  self._builder.emit_statement(
115
122
  control.copy(update=dict(body=[wrapping_function]))
@@ -208,7 +215,7 @@ class ControlEmitter(ExpressionOperationEmitter[Control]):
208
215
  arith_expression = ArithmeticOperation(
209
216
  result_var=HandleBinding(name=aux_var),
210
217
  expression=control.expression,
211
- inplace_result=False,
218
+ operation_kind=ArithmeticOperationKind.Assignment,
212
219
  )
213
220
  self._interpreter.emit_statement(
214
221
  WithinApply(
@@ -1,5 +1,15 @@
1
1
  from abc import abstractmethod
2
- from typing import TYPE_CHECKING, Generic, List, Sequence, TypeVar, cast
2
+ from typing import (
3
+ TYPE_CHECKING,
4
+ Dict,
5
+ Generic,
6
+ List,
7
+ Optional,
8
+ Sequence,
9
+ TypeVar,
10
+ Union,
11
+ cast,
12
+ )
3
13
 
4
14
  from classiq.interface.debug_info.debug_info import FunctionDebugInfo
5
15
  from classiq.interface.ide.visual_model import OperationLevel
@@ -14,7 +24,7 @@ from classiq.interface.model.quantum_function_declaration import (
14
24
  NamedParamsQuantumFunctionDeclaration,
15
25
  PositionalArg,
16
26
  )
17
- from classiq.interface.model.quantum_statement import QuantumStatement
27
+ from classiq.interface.model.quantum_statement import QuantumOperation, QuantumStatement
18
28
  from classiq.interface.model.variable_declaration_statement import (
19
29
  VariableDeclarationStatement,
20
30
  )
@@ -23,7 +33,7 @@ from classiq.model_expansions.capturing.propagated_var_stack import (
23
33
  PropagatedVarStack,
24
34
  validate_args_are_not_propagated,
25
35
  )
26
- from classiq.model_expansions.closure import FunctionClosure
36
+ from classiq.model_expansions.closure import Closure, FunctionClosure, GenerativeClosure
27
37
  from classiq.model_expansions.evaluators.argument_types import (
28
38
  add_information_from_output_arguments,
29
39
  )
@@ -33,10 +43,13 @@ from classiq.model_expansions.evaluators.parameter_types import (
33
43
  from classiq.model_expansions.function_builder import (
34
44
  FunctionContext,
35
45
  OperationBuilder,
46
+ OperationContext,
36
47
  )
48
+ from classiq.model_expansions.generative_functions import emit_operands_as_declarative
37
49
  from classiq.model_expansions.scope import Evaluated, QuantumSymbol, Scope
38
50
  from classiq.model_expansions.utils.counted_name_allocator import CountedNameAllocator
39
51
  from classiq.qmod.builtins.functions import allocate, free
52
+ from classiq.qmod.quantum_function import GenerativeQFunc
40
53
 
41
54
  if TYPE_CHECKING:
42
55
  from classiq.model_expansions.interpreter import Interpreter
@@ -50,13 +63,24 @@ class Emitter(Generic[QuantumStatementT]):
50
63
  self._interpreter = interpreter
51
64
 
52
65
  self._scope_guard = self._interpreter._scope_guard
53
- self._expand_operation = self._interpreter._expand_operation
54
66
  self._machine_precision = self._interpreter._model.preferences.machine_precision
55
67
 
68
+ self._generative_contexts: Dict[str, OperationContext] = {}
69
+
56
70
  @abstractmethod
57
71
  def emit(self, statement: QuantumStatementT, /) -> None:
58
72
  pass
59
73
 
74
+ def _expand_operation(self, closure: Closure) -> OperationContext:
75
+ if closure.name in self._generative_contexts:
76
+ if isinstance(closure, FunctionClosure):
77
+ return FunctionContext(
78
+ closure=closure,
79
+ blocks=self._generative_contexts[closure.name].blocks,
80
+ )
81
+ return self._generative_contexts[closure.name]
82
+ return self._interpreter._expand_operation(closure)
83
+
60
84
  @property
61
85
  def _propagated_var_stack(self) -> PropagatedVarStack:
62
86
  return self._interpreter._propagated_var_stack
@@ -181,7 +205,10 @@ class Emitter(Generic[QuantumStatementT]):
181
205
  new_positional_arg_decls, evaluated_args
182
206
  )
183
207
  if is_atomic:
184
- return [arg.emit() for arg in evaluated_args]
208
+ return [
209
+ emit_operands_as_declarative(self._interpreter, param, arg)
210
+ for param, arg in zip(new_positional_arg_decls, evaluated_args)
211
+ ]
185
212
 
186
213
  positional_args = [
187
214
  arg.emit() for arg in evaluated_args if isinstance(arg.value, QuantumSymbol)
@@ -219,3 +246,31 @@ class Emitter(Generic[QuantumStatementT]):
219
246
  evaluated_args,
220
247
  ),
221
248
  )
249
+
250
+ def _register_generative_context(
251
+ self,
252
+ op: QuantumOperation,
253
+ context_name: str,
254
+ block_names: Union[None, str, List[str]] = None,
255
+ func_decl: Optional[NamedParamsQuantumFunctionDeclaration] = None,
256
+ ) -> OperationContext:
257
+ if isinstance(block_names, str):
258
+ block_names = [block_names]
259
+ block_names = block_names or ["body"]
260
+ func_decl = func_decl or NamedParamsQuantumFunctionDeclaration(
261
+ name=context_name
262
+ )
263
+ gen_closure = GenerativeClosure(
264
+ name=func_decl.name,
265
+ scope=Scope(parent=self._interpreter._current_scope),
266
+ blocks={},
267
+ generative_blocks={
268
+ block_name: GenerativeQFunc(
269
+ op.get_generative_block(block_name), func_decl
270
+ )
271
+ for block_name in block_names
272
+ },
273
+ )
274
+ context = self._interpreter._expand_operation(gen_closure)
275
+ self._generative_contexts[context_name] = context
276
+ return context
@@ -58,17 +58,20 @@ class ExpressionOperationEmitter(Emitter[ExpressionOperationT]):
58
58
  symbols_parts, bind_ops = self._get_bind_ops(symbols_to_split)
59
59
 
60
60
  for symbol_parts in symbols_parts:
61
- for symbol in symbol_parts:
61
+ for symbol, symbol_part_var_name in symbol_parts:
62
62
  if symbol.handle.identifier not in self._current_scope:
63
63
  self._interpreter.emit_statement(
64
64
  VariableDeclarationStatement(
65
- name=symbol.handle.identifier,
65
+ name=symbol_part_var_name,
66
66
  quantum_type=symbol.quantum_type,
67
67
  )
68
68
  )
69
69
 
70
70
  new_expression = self._update_op_expression(
71
- {symbol.handle: symbol for symbol in chain.from_iterable(symbols_parts)},
71
+ {
72
+ symbol.handle: symbol_part_var_name
73
+ for symbol, symbol_part_var_name in chain.from_iterable(symbols_parts)
74
+ },
72
75
  expression,
73
76
  )
74
77
  new_op = op.copy(update=dict(expression=new_expression))
@@ -83,7 +86,7 @@ class ExpressionOperationEmitter(Emitter[ExpressionOperationT]):
83
86
 
84
87
  def _update_op_expression(
85
88
  self,
86
- symbol_parts: Dict[HandleBinding, QuantumSymbol],
89
+ symbol_parts: Dict[HandleBinding, str],
87
90
  expression: Expression,
88
91
  ) -> Expression:
89
92
  vrc = VarRefCollector(ignore_duplicated_handles=True)
@@ -94,7 +97,7 @@ class ExpressionOperationEmitter(Emitter[ExpressionOperationT]):
94
97
  collapsed_handle = handle.collapse()
95
98
  if collapsed_handle in symbol_parts:
96
99
  new_expr_str = new_expr_str.replace(
97
- str(handle), symbol_parts[collapsed_handle].handle.identifier
100
+ str(handle), symbol_parts[collapsed_handle]
98
101
  )
99
102
  self._check_all_handles_were_replaced(new_expr_str)
100
103
 
@@ -115,32 +118,38 @@ class ExpressionOperationEmitter(Emitter[ExpressionOperationT]):
115
118
  ):
116
119
  raise ClassiqInternalExpansionError(f"Did not replace handle {handle}")
117
120
 
118
- @staticmethod
119
121
  def _get_bind_ops(
122
+ self,
120
123
  symbols_to_split: List[QuantumSymbol],
121
- ) -> Tuple[List[List[QuantumSymbol]], List[BindOperation]]:
124
+ ) -> Tuple[List[List[Tuple[QuantumSymbol, str]]], List[BindOperation]]:
122
125
  bind_ops = []
123
126
  symbols_parts = []
124
127
  for symbol in symbols_to_split:
125
- symbol_parts = ExpressionOperationEmitter._get_symbol_parts(symbol)
128
+ symbol_parts = self._get_symbol_parts(symbol)
126
129
  symbols_parts.append(symbol_parts)
127
130
  bind_ops.append(
128
131
  BindOperation(
129
132
  in_handles=[symbol.handle],
130
133
  out_handles=[
131
- HandleBinding(name=symbol_part.handle.identifier)
132
- for symbol_part in symbol_parts
134
+ HandleBinding(name=symbol_part_var_name)
135
+ for _, symbol_part_var_name in symbol_parts
133
136
  ],
134
137
  )
135
138
  )
136
139
  return symbols_parts, bind_ops
137
140
 
138
- @staticmethod
139
- def _get_symbol_parts(symbol: QuantumSymbol) -> List[QuantumSymbol]:
141
+ def _get_symbol_parts(
142
+ self, symbol: QuantumSymbol
143
+ ) -> List[Tuple[QuantumSymbol, str]]:
140
144
  quantum_type = symbol.quantum_type
141
145
 
142
146
  if isinstance(quantum_type, (QuantumBit, QuantumNumeric)):
143
- return [symbol]
147
+ return [
148
+ (
149
+ symbol,
150
+ self._counted_name_allocator.allocate(symbol.handle.identifier),
151
+ )
152
+ ]
144
153
 
145
154
  if isinstance(quantum_type, QuantumBitvector):
146
155
  if not quantum_type.has_length:
@@ -150,7 +159,7 @@ class ExpressionOperationEmitter(Emitter[ExpressionOperationT]):
150
159
  )
151
160
  return list(
152
161
  chain.from_iterable(
153
- ExpressionOperationEmitter._get_symbol_parts(symbol[idx])
162
+ self._get_symbol_parts(symbol[idx])
154
163
  for idx in range(quantum_type.length_value)
155
164
  )
156
165
  )
@@ -160,7 +169,7 @@ class ExpressionOperationEmitter(Emitter[ExpressionOperationT]):
160
169
 
161
170
  return list(
162
171
  chain.from_iterable(
163
- ExpressionOperationEmitter._get_symbol_parts(field_symbol)
172
+ self._get_symbol_parts(field_symbol)
164
173
  for field_symbol in symbol.fields.values()
165
174
  )
166
175
  )
@@ -204,7 +213,7 @@ class ExpressionOperationEmitter(Emitter[ExpressionOperationT]):
204
213
  op_with_evaluated_types = op.copy(update={"expression": expression})
205
214
  vrc = VarRefCollector()
206
215
  vrc.visit(ast.parse(op_with_evaluated_types.expression.expr))
207
- handles = list(vrc.var_handles)
216
+ handles = vrc.var_handles
208
217
  op_with_evaluated_types.set_var_handles(handles)
209
218
  op_with_evaluated_types.initialize_var_types(
210
219
  {