classiq 0.56.1__py3-none-any.whl → 0.58.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 (46) hide show
  1. classiq/analyzer/show_interactive_hack.py +16 -4
  2. classiq/applications/combinatorial_helpers/encoding_utils.py +1 -0
  3. classiq/applications/combinatorial_helpers/transformations/encoding.py +3 -1
  4. classiq/execution/jobs.py +8 -1
  5. classiq/executor.py +1 -1
  6. classiq/interface/_version.py +1 -1
  7. classiq/interface/backend/backend_preferences.py +27 -5
  8. classiq/interface/backend/pydantic_backend.py +0 -1
  9. classiq/interface/execution/jobs.py +4 -1
  10. classiq/interface/executor/execution_request.py +19 -5
  11. classiq/interface/generator/arith/arithmetic_expression_validator.py +28 -9
  12. classiq/interface/generator/functions/type_name.py +7 -9
  13. classiq/interface/generator/types/builtin_enum_declarations.py +1 -0
  14. classiq/model_expansions/closure.py +24 -6
  15. classiq/model_expansions/evaluators/parameter_types.py +1 -2
  16. classiq/model_expansions/evaluators/quantum_type_utils.py +0 -7
  17. classiq/model_expansions/function_builder.py +13 -0
  18. classiq/model_expansions/interpreter.py +9 -14
  19. classiq/model_expansions/quantum_operations/call_emitter.py +207 -0
  20. classiq/model_expansions/quantum_operations/classicalif.py +2 -2
  21. classiq/model_expansions/quantum_operations/control.py +7 -5
  22. classiq/model_expansions/quantum_operations/emitter.py +1 -186
  23. classiq/model_expansions/quantum_operations/expression_operation.py +26 -189
  24. classiq/model_expansions/quantum_operations/inplace_binary_operation.py +2 -2
  25. classiq/model_expansions/quantum_operations/invert.py +2 -2
  26. classiq/model_expansions/quantum_operations/phase.py +3 -1
  27. classiq/model_expansions/quantum_operations/power.py +2 -2
  28. classiq/model_expansions/quantum_operations/quantum_assignment_operation.py +7 -9
  29. classiq/model_expansions/quantum_operations/quantum_function_call.py +2 -2
  30. classiq/model_expansions/quantum_operations/repeat.py +2 -2
  31. classiq/model_expansions/transformers/__init__.py +0 -0
  32. classiq/model_expansions/transformers/var_splitter.py +237 -0
  33. classiq/qmod/builtins/classical_functions.py +1 -0
  34. classiq/qmod/builtins/functions/state_preparation.py +1 -1
  35. classiq/qmod/create_model_function.py +25 -20
  36. classiq/qmod/native/pretty_printer.py +19 -4
  37. classiq/qmod/pretty_print/pretty_printer.py +53 -28
  38. classiq/qmod/qfunc.py +18 -16
  39. classiq/qmod/quantum_function.py +30 -24
  40. classiq/qmod/semantics/qstruct_annotator.py +23 -0
  41. classiq/qmod/semantics/static_semantics_visitor.py +4 -1
  42. classiq/qmod/write_qmod.py +3 -1
  43. classiq/synthesis.py +3 -1
  44. {classiq-0.56.1.dist-info → classiq-0.58.0.dist-info}/METADATA +1 -1
  45. {classiq-0.56.1.dist-info → classiq-0.58.0.dist-info}/RECORD +46 -42
  46. {classiq-0.56.1.dist-info → classiq-0.58.0.dist-info}/WHEEL +0 -0
@@ -0,0 +1,207 @@
1
+ from collections.abc import Sequence
2
+ from typing import (
3
+ Generic,
4
+ cast,
5
+ )
6
+
7
+ from classiq.interface.debug_info.debug_info import FunctionDebugInfo
8
+ from classiq.interface.generator.generated_circuit_data import OperationLevel
9
+ from classiq.interface.model.classical_parameter_declaration import (
10
+ ClassicalParameterDeclaration,
11
+ )
12
+ from classiq.interface.model.handle_binding import HandleBinding
13
+ from classiq.interface.model.port_declaration import PortDeclaration
14
+ from classiq.interface.model.quantum_function_call import ArgValue, QuantumFunctionCall
15
+ from classiq.interface.model.quantum_function_declaration import (
16
+ NamedParamsQuantumFunctionDeclaration,
17
+ PositionalArg,
18
+ )
19
+ from classiq.interface.model.quantum_statement import QuantumStatement
20
+ from classiq.interface.model.variable_declaration_statement import (
21
+ VariableDeclarationStatement,
22
+ )
23
+
24
+ from classiq.model_expansions.capturing.propagated_var_stack import (
25
+ validate_args_are_not_propagated,
26
+ )
27
+ from classiq.model_expansions.closure import FunctionClosure
28
+ from classiq.model_expansions.evaluators.argument_types import (
29
+ add_information_from_output_arguments,
30
+ )
31
+ from classiq.model_expansions.evaluators.parameter_types import (
32
+ evaluate_parameter_types_from_args,
33
+ )
34
+ from classiq.model_expansions.function_builder import (
35
+ FunctionContext,
36
+ )
37
+ from classiq.model_expansions.generative_functions import emit_operands_as_declarative
38
+ from classiq.model_expansions.quantum_operations.emitter import (
39
+ Emitter,
40
+ QuantumStatementT,
41
+ )
42
+ from classiq.model_expansions.scope import Evaluated, QuantumSymbol, Scope
43
+ from classiq.qmod.builtins.functions import allocate, free
44
+
45
+
46
+ class CallEmitter(Generic[QuantumStatementT], Emitter[QuantumStatementT]):
47
+ @staticmethod
48
+ def _should_wrap(body: Sequence[QuantumStatement]) -> bool:
49
+ # This protects shadowing of captured variables (i.e, bad user code) by wrapping the body in a function
50
+ # I'm sure there are better ways to handle it, but this is the simplest way to do it for now
51
+ return any(isinstance(stmt, VariableDeclarationStatement) for stmt in body)
52
+
53
+ def _create_expanded_wrapping_function(
54
+ self, name: str, body: Sequence[QuantumStatement]
55
+ ) -> QuantumFunctionCall:
56
+ wrapping_function = FunctionClosure.create(
57
+ name=name, body=body, scope=Scope(parent=self._current_scope)
58
+ )
59
+ return self._create_quantum_function_call(wrapping_function, list())
60
+
61
+ def _emit_quantum_function_call(
62
+ self, function: FunctionClosure, args: list[ArgValue]
63
+ ) -> QuantumFunctionCall:
64
+ call = self._create_quantum_function_call(function, args)
65
+ self._builder.emit_statement(call)
66
+ return call
67
+
68
+ def _create_quantum_function_call(
69
+ self, function: FunctionClosure, args: list[ArgValue]
70
+ ) -> QuantumFunctionCall:
71
+ evaluated_args = [self._interpreter.evaluate(arg) for arg in args]
72
+ new_declaration = self._prepare_fully_typed_declaration(
73
+ function, evaluated_args
74
+ )
75
+ new_positional_arg_decls = new_declaration.positional_arg_declarations
76
+ is_atomic = function.is_atomic
77
+ new_function_name = function.name
78
+ if not is_atomic: # perform monomorphization per interpreted parameters set
79
+ self._add_params_to_scope(
80
+ new_positional_arg_decls, evaluated_args, function
81
+ )
82
+ context = self._expand_operation(
83
+ function.with_new_declaration(new_declaration)
84
+ )
85
+ function_context = cast(FunctionContext, context)
86
+ closure_id = function_context.closure.closure_id
87
+ function_def = self._expanded_functions.get(closure_id)
88
+ if function_def is None:
89
+ function_def = self._builder.create_definition(function_context)
90
+ self._expanded_functions[closure_id] = function_def
91
+ self._top_level_scope[function_def.name] = Evaluated(
92
+ value=function_context.closure.with_new_declaration(function_def)
93
+ )
94
+ new_declaration = function_def
95
+ new_function_name = function_def.name
96
+ compilation_metadata = self._functions_compilation_metadata.get(
97
+ function.name
98
+ )
99
+ if compilation_metadata is not None:
100
+ self._expanded_functions_compilation_metadata[new_function_name] = (
101
+ compilation_metadata
102
+ )
103
+
104
+ new_positional_args = self._get_new_positional_args(
105
+ evaluated_args, is_atomic, new_positional_arg_decls
106
+ )
107
+ new_call = QuantumFunctionCall(
108
+ function=new_function_name,
109
+ positional_args=new_positional_args,
110
+ )
111
+ is_allocate_or_free = (
112
+ new_call.func_name == allocate.func_decl.name
113
+ or new_call.func_name == free.func_decl.name
114
+ )
115
+ parameters = {
116
+ arg_decl.name: FunctionDebugInfo.param_controller(value=evaluated_arg.value)
117
+ for arg_decl, evaluated_arg in zip(new_positional_arg_decls, evaluated_args)
118
+ if isinstance(arg_decl, ClassicalParameterDeclaration)
119
+ }
120
+
121
+ port_to_passed_variable_map = {
122
+ arg_decl.name: str(evaluated_arg.value.handle)
123
+ for arg_decl, evaluated_arg in zip(new_positional_arg_decls, evaluated_args)
124
+ if isinstance(arg_decl, PortDeclaration)
125
+ }
126
+ self._interpreter._model.debug_info[new_call.uuid] = FunctionDebugInfo(
127
+ name=new_call.func_name,
128
+ level=OperationLevel.QMOD_FUNCTION_CALL,
129
+ parameters=parameters,
130
+ is_allocate_or_free=is_allocate_or_free,
131
+ port_to_passed_variable_map=port_to_passed_variable_map,
132
+ )
133
+ new_call.set_func_decl(new_declaration)
134
+ return new_call
135
+
136
+ @staticmethod
137
+ def _add_params_to_scope(
138
+ parameters: Sequence[PositionalArg],
139
+ arguments: Sequence[Evaluated],
140
+ closure: FunctionClosure,
141
+ ) -> None:
142
+ for parameter, argument in zip(parameters, arguments):
143
+ if isinstance(argument.value, QuantumSymbol):
144
+ assert isinstance(parameter, PortDeclaration)
145
+ closure.scope[parameter.name] = Evaluated(
146
+ QuantumSymbol(
147
+ handle=HandleBinding(name=parameter.name),
148
+ quantum_type=parameter.quantum_type,
149
+ ),
150
+ defining_function=closure,
151
+ )
152
+ else:
153
+ closure.scope[parameter.name] = argument
154
+
155
+ def _get_new_positional_args(
156
+ self,
157
+ evaluated_args: list[Evaluated],
158
+ is_atomic: bool,
159
+ new_positional_arg_decls: Sequence[PositionalArg],
160
+ ) -> list[ArgValue]:
161
+ evaluated_args = add_information_from_output_arguments(
162
+ new_positional_arg_decls, evaluated_args
163
+ )
164
+ if is_atomic:
165
+ return [
166
+ emit_operands_as_declarative(self._interpreter, param, arg)
167
+ for param, arg in zip(new_positional_arg_decls, evaluated_args)
168
+ ]
169
+
170
+ positional_args = [
171
+ arg.emit() for arg in evaluated_args if isinstance(arg.value, QuantumSymbol)
172
+ ]
173
+
174
+ propagated_variables = self._propagated_var_stack.get_propagated_variables(
175
+ flatten=True
176
+ )
177
+ validate_args_are_not_propagated(positional_args, propagated_variables)
178
+ positional_args.extend(propagated_variables)
179
+
180
+ return positional_args
181
+
182
+ def _prepare_fully_typed_declaration(
183
+ self, function: FunctionClosure, evaluated_args: list[Evaluated]
184
+ ) -> NamedParamsQuantumFunctionDeclaration:
185
+ """
186
+ Given, for example,
187
+ def my_func(x: int, q: QArray["x"], p: QArray[]) -> None:
188
+ ...
189
+ def main(...):
190
+ ...
191
+ allocate(5, s)
192
+ my_func(3, r, s)
193
+ The code below will evaluate x to be 3, q to be of size 3 and p to be of size 5.
194
+ Note that it requires a scope for the parameter declaration space, which is
195
+ different from the call scope. For example, the former uses r,s and the latter
196
+ uses p, q.
197
+ """
198
+ with self._scope_guard(Scope(parent=self._current_scope)):
199
+ # The signature scope is passed as a separate argument to avoid contaminating the statement execution scope
200
+ return NamedParamsQuantumFunctionDeclaration(
201
+ name=function.name,
202
+ positional_arg_declarations=evaluate_parameter_types_from_args(
203
+ function,
204
+ function.signature_scope,
205
+ evaluated_args,
206
+ ),
207
+ )
@@ -5,7 +5,7 @@ from classiq.interface.model.quantum_function_call import QuantumFunctionCall
5
5
  from classiq.interface.model.quantum_statement import QuantumStatement
6
6
 
7
7
  from classiq.model_expansions.closure import FunctionClosure
8
- from classiq.model_expansions.quantum_operations.emitter import Emitter
8
+ from classiq.model_expansions.quantum_operations.call_emitter import CallEmitter
9
9
  from classiq.model_expansions.scope import Scope
10
10
 
11
11
 
@@ -16,7 +16,7 @@ def _is_all_identity_calls(body: Sequence[QuantumStatement]) -> bool:
16
16
  )
17
17
 
18
18
 
19
- class ClassicalIfEmitter(Emitter[ClassicalIf]):
19
+ class ClassicalIfEmitter(CallEmitter[ClassicalIf]):
20
20
  def emit(self, classical_if: ClassicalIf, /) -> None:
21
21
  with self._propagated_var_stack.capture_variables(classical_if):
22
22
  self._emit_propagated(classical_if)
@@ -26,7 +26,6 @@ from classiq.interface.model.quantum_function_call import QuantumFunctionCall
26
26
  from classiq.interface.model.quantum_type import (
27
27
  QuantumBit,
28
28
  QuantumBitvector,
29
- QuantumType,
30
29
  )
31
30
  from classiq.interface.model.statement_block import ConcreteQuantumStatement
32
31
  from classiq.interface.model.variable_declaration_statement import (
@@ -47,6 +46,7 @@ from classiq.model_expansions.quantum_operations.expression_operation import (
47
46
  ExpressionOperationEmitter,
48
47
  )
49
48
  from classiq.model_expansions.scope import Scope
49
+ from classiq.model_expansions.transformers.var_splitter import SymbolParts
50
50
  from classiq.qmod.builtins.functions.standard_gates import X
51
51
 
52
52
 
@@ -54,7 +54,9 @@ class ControlEmitter(ExpressionOperationEmitter[Control]):
54
54
  def emit(self, control: Control, /) -> None:
55
55
  condition = self._evaluate_op_expression(control)
56
56
 
57
- arrays_with_subscript = self._get_symbols_to_split(condition)
57
+ arrays_with_subscript = self.split_symbols(
58
+ condition, self._counted_name_allocator.allocate
59
+ )
58
60
  if len(arrays_with_subscript) > 0:
59
61
  if control.is_generative():
60
62
  with self._propagated_var_stack.capture_variables(control):
@@ -308,12 +310,12 @@ class ControlEmitter(ExpressionOperationEmitter[Control]):
308
310
  raise ClassiqExpansionError(_condition_err_msg(condition_val))
309
311
 
310
312
  def _get_updated_op_split_symbols(
311
- self, op: Control, symbol_mapping: dict[HandleBinding, tuple[str, QuantumType]]
313
+ self, op: Control, symbol_parts: SymbolParts
312
314
  ) -> Control:
313
- new_body = self._rewrite(op.body, symbol_mapping)
315
+ new_body = self.rewrite(op.body, symbol_parts)
314
316
  new_else = None
315
317
  if op.else_block is not None:
316
- new_else = self._rewrite(op.else_block, symbol_mapping)
318
+ new_else = self.rewrite(op.else_block, symbol_parts)
317
319
  return op.model_copy(update=dict(body=new_body, else_block=new_else))
318
320
 
319
321
 
@@ -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,