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.
- classiq/analyzer/show_interactive_hack.py +16 -4
- classiq/applications/combinatorial_helpers/encoding_utils.py +1 -0
- classiq/applications/combinatorial_helpers/transformations/encoding.py +3 -1
- classiq/execution/jobs.py +8 -1
- classiq/executor.py +1 -1
- classiq/interface/_version.py +1 -1
- classiq/interface/backend/backend_preferences.py +27 -5
- classiq/interface/backend/pydantic_backend.py +0 -1
- classiq/interface/execution/jobs.py +4 -1
- classiq/interface/executor/execution_request.py +19 -5
- classiq/interface/generator/arith/arithmetic_expression_validator.py +28 -9
- classiq/interface/generator/functions/type_name.py +7 -9
- classiq/interface/generator/types/builtin_enum_declarations.py +1 -0
- classiq/model_expansions/closure.py +24 -6
- classiq/model_expansions/evaluators/parameter_types.py +1 -2
- classiq/model_expansions/evaluators/quantum_type_utils.py +0 -7
- classiq/model_expansions/function_builder.py +13 -0
- classiq/model_expansions/interpreter.py +9 -14
- classiq/model_expansions/quantum_operations/call_emitter.py +207 -0
- classiq/model_expansions/quantum_operations/classicalif.py +2 -2
- classiq/model_expansions/quantum_operations/control.py +7 -5
- classiq/model_expansions/quantum_operations/emitter.py +1 -186
- classiq/model_expansions/quantum_operations/expression_operation.py +26 -189
- classiq/model_expansions/quantum_operations/inplace_binary_operation.py +2 -2
- classiq/model_expansions/quantum_operations/invert.py +2 -2
- classiq/model_expansions/quantum_operations/phase.py +3 -1
- classiq/model_expansions/quantum_operations/power.py +2 -2
- classiq/model_expansions/quantum_operations/quantum_assignment_operation.py +7 -9
- classiq/model_expansions/quantum_operations/quantum_function_call.py +2 -2
- classiq/model_expansions/quantum_operations/repeat.py +2 -2
- classiq/model_expansions/transformers/__init__.py +0 -0
- classiq/model_expansions/transformers/var_splitter.py +237 -0
- classiq/qmod/builtins/classical_functions.py +1 -0
- classiq/qmod/builtins/functions/state_preparation.py +1 -1
- classiq/qmod/create_model_function.py +25 -20
- classiq/qmod/native/pretty_printer.py +19 -4
- classiq/qmod/pretty_print/pretty_printer.py +53 -28
- classiq/qmod/qfunc.py +18 -16
- classiq/qmod/quantum_function.py +30 -24
- classiq/qmod/semantics/qstruct_annotator.py +23 -0
- classiq/qmod/semantics/static_semantics_visitor.py +4 -1
- classiq/qmod/write_qmod.py +3 -1
- classiq/synthesis.py +3 -1
- {classiq-0.56.1.dist-info → classiq-0.58.0.dist-info}/METADATA +1 -1
- {classiq-0.56.1.dist-info → classiq-0.58.0.dist-info}/RECORD +46 -42
- {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.
|
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(
|
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.
|
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,
|
313
|
+
self, op: Control, symbol_parts: SymbolParts
|
312
314
|
) -> Control:
|
313
|
-
new_body = self.
|
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.
|
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.
|
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,
|