classiq 0.54.0__py3-none-any.whl → 0.56.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/interface/_version.py +1 -1
- classiq/interface/debug_info/debug_info.py +11 -0
- classiq/interface/executor/result.py +0 -3
- classiq/interface/generator/functions/builtins/internal_operators.py +9 -1
- classiq/interface/generator/generated_circuit_data.py +0 -1
- classiq/interface/generator/model/preferences/preferences.py +4 -0
- classiq/interface/generator/types/compilation_metadata.py +5 -0
- classiq/interface/generator/visitor.py +13 -1
- classiq/interface/ide/visual_model.py +5 -1
- classiq/interface/interface_version.py +1 -1
- classiq/interface/model/control.py +22 -1
- classiq/interface/model/handle_binding.py +28 -0
- classiq/interface/model/model.py +4 -0
- classiq/interface/model/native_function_definition.py +1 -1
- classiq/interface/model/quantum_expressions/arithmetic_operation.py +2 -26
- classiq/interface/model/quantum_statement.py +6 -0
- classiq/model_expansions/capturing/mangling_utils.py +22 -0
- classiq/model_expansions/capturing/propagated_var_stack.py +36 -25
- classiq/model_expansions/closure.py +77 -12
- classiq/model_expansions/function_builder.py +9 -10
- classiq/model_expansions/generative_functions.py +2 -2
- classiq/model_expansions/interpreter.py +29 -26
- classiq/model_expansions/quantum_operations/control.py +114 -29
- classiq/model_expansions/quantum_operations/emitter.py +37 -11
- classiq/model_expansions/quantum_operations/expression_operation.py +80 -18
- classiq/model_expansions/quantum_operations/power.py +5 -0
- classiq/model_expansions/quantum_operations/quantum_assignment_operation.py +7 -37
- classiq/model_expansions/quantum_operations/quantum_function_call.py +2 -32
- classiq/model_expansions/quantum_operations/repeat.py +5 -0
- classiq/model_expansions/quantum_operations/within_apply.py +0 -16
- classiq/model_expansions/scope_initialization.py +2 -3
- classiq/qmod/builtins/functions/arithmetic.py +0 -2
- classiq/qmod/builtins/functions/discrete_sine_cosine_transform.py +0 -12
- classiq/qmod/builtins/functions/exponentiation.py +0 -6
- classiq/qmod/builtins/functions/grover.py +0 -17
- classiq/qmod/builtins/functions/linear_pauli_rotation.py +0 -5
- classiq/qmod/builtins/functions/modular_exponentiation.py +0 -3
- classiq/qmod/builtins/functions/qaoa_penalty.py +0 -8
- classiq/qmod/builtins/functions/qft_functions.py +0 -3
- classiq/qmod/builtins/functions/qpe.py +0 -6
- classiq/qmod/builtins/functions/qsvt.py +0 -12
- classiq/qmod/builtins/functions/standard_gates.py +0 -88
- classiq/qmod/builtins/functions/state_preparation.py +7 -15
- classiq/qmod/builtins/functions/swap_test.py +0 -3
- classiq/qmod/builtins/operations.py +152 -17
- classiq/qmod/create_model_function.py +10 -12
- classiq/qmod/model_state_container.py +5 -1
- classiq/qmod/native/pretty_printer.py +6 -1
- classiq/qmod/pretty_print/pretty_printer.py +25 -11
- classiq/qmod/qmod_constant.py +31 -3
- classiq/qmod/quantum_function.py +25 -19
- classiq/qmod/synthesize_separately.py +1 -2
- {classiq-0.54.0.dist-info → classiq-0.56.0.dist-info}/METADATA +2 -3
- {classiq-0.54.0.dist-info → classiq-0.56.0.dist-info}/RECORD +55 -55
- classiq/model_expansions/call_to_model_converter.py +0 -190
- {classiq-0.54.0.dist-info → classiq-0.56.0.dist-info}/WHEEL +0 -0
@@ -19,7 +19,6 @@ from classiq.interface.generator.functions.port_declaration import (
|
|
19
19
|
)
|
20
20
|
from classiq.interface.model.model import MAIN_FUNCTION_NAME
|
21
21
|
from classiq.interface.model.native_function_definition import (
|
22
|
-
FunctionSynthesisData,
|
23
22
|
NativeFunctionDefinition,
|
24
23
|
)
|
25
24
|
from classiq.interface.model.port_declaration import PortDeclaration
|
@@ -31,6 +30,7 @@ from classiq.interface.model.quantum_statement import QuantumStatement
|
|
31
30
|
from classiq.model_expansions.capturing.captured_var_manager import update_captured_vars
|
32
31
|
from classiq.model_expansions.capturing.mangling_utils import demangle_name
|
33
32
|
from classiq.model_expansions.closure import Closure, FunctionClosure
|
33
|
+
from classiq.model_expansions.scope import Scope
|
34
34
|
|
35
35
|
ClosureType = TypeVar("ClosureType", bound=Closure)
|
36
36
|
|
@@ -76,16 +76,12 @@ class FunctionContext(OperationContext[FunctionClosure]):
|
|
76
76
|
def is_lambda(self) -> bool:
|
77
77
|
return self.closure.is_lambda
|
78
78
|
|
79
|
-
@property
|
80
|
-
def synthesis_data(self) -> FunctionSynthesisData:
|
81
|
-
return self.closure.synthesis_data
|
82
|
-
|
83
79
|
|
84
80
|
class OperationBuilder:
|
85
|
-
def __init__(self) -> None:
|
81
|
+
def __init__(self, functions_scope: Scope) -> None:
|
86
82
|
self._operations: list[OperationContext] = []
|
87
83
|
self._blocks: list[str] = []
|
88
|
-
self.
|
84
|
+
self._functions_scope = functions_scope
|
89
85
|
|
90
86
|
@property
|
91
87
|
def current_operation(self) -> Closure:
|
@@ -163,8 +159,12 @@ class OperationBuilder:
|
|
163
159
|
) -> NativeFunctionDefinition:
|
164
160
|
name = function_context.name
|
165
161
|
if name != MAIN_FUNCTION_NAME:
|
166
|
-
|
167
|
-
|
162
|
+
idx = 0
|
163
|
+
new_name = name
|
164
|
+
while idx == 0 or new_name in self._functions_scope:
|
165
|
+
new_name = f"{name}_{LAMBDA_KEYWORD + '_0_0_' if function_context.is_lambda else ''}{EXPANDED_KEYWORD}_{idx}"
|
166
|
+
idx += 1
|
167
|
+
name = new_name
|
168
168
|
|
169
169
|
new_parameters: list[PortDeclaration] = [
|
170
170
|
param
|
@@ -176,7 +176,6 @@ class OperationBuilder:
|
|
176
176
|
name=name,
|
177
177
|
body=function_context.body,
|
178
178
|
positional_arg_declarations=new_parameters,
|
179
|
-
synthesis_data=function_context.synthesis_data,
|
180
179
|
)
|
181
180
|
|
182
181
|
|
@@ -186,7 +186,7 @@ def _expand_operand_as_declarative(
|
|
186
186
|
|
187
187
|
|
188
188
|
def _register_declarative_function(interpreter: "Interpreter", func_name: str) -> None:
|
189
|
-
if func_name in nameables_to_dict(interpreter._expanded_functions):
|
189
|
+
if func_name in nameables_to_dict(list(interpreter._expanded_functions.values())):
|
190
190
|
return
|
191
191
|
|
192
192
|
for user_gen_func in interpreter._generative_functions:
|
@@ -199,7 +199,7 @@ def _register_declarative_function(interpreter: "Interpreter", func_name: str) -
|
|
199
199
|
dec_func = QFunc(user_gen_func._py_callable)
|
200
200
|
dec_func.expand()
|
201
201
|
dec_func_def = QMODULE.native_defs[func_name]
|
202
|
-
interpreter._expanded_functions
|
202
|
+
interpreter._expanded_functions[func_name] = dec_func_def
|
203
203
|
_DecFuncVisitor(interpreter).visit(dec_func_def)
|
204
204
|
|
205
205
|
|
@@ -11,7 +11,9 @@ from classiq.interface.exceptions import (
|
|
11
11
|
ClassiqExpansionError,
|
12
12
|
ClassiqInternalExpansionError,
|
13
13
|
)
|
14
|
+
from classiq.interface.generator.constant import Constant
|
14
15
|
from classiq.interface.generator.expressions.expression import Expression
|
16
|
+
from classiq.interface.generator.types.compilation_metadata import CompilationMetadata
|
15
17
|
from classiq.interface.model.bind_operation import BindOperation
|
16
18
|
from classiq.interface.model.classical_if import ClassicalIf
|
17
19
|
from classiq.interface.model.control import Control
|
@@ -46,7 +48,6 @@ from classiq.interface.model.variable_declaration_statement import (
|
|
46
48
|
)
|
47
49
|
from classiq.interface.model.within_apply_operation import WithinApply
|
48
50
|
|
49
|
-
from classiq.model_expansions.call_to_model_converter import BlockFunctionInfo
|
50
51
|
from classiq.model_expansions.capturing.propagated_var_stack import PropagatedVarStack
|
51
52
|
from classiq.model_expansions.closure import (
|
52
53
|
Closure,
|
@@ -81,6 +82,7 @@ from classiq.model_expansions.quantum_operations import (
|
|
81
82
|
from classiq.model_expansions.quantum_operations.phase import PhaseEmitter
|
82
83
|
from classiq.model_expansions.scope import Evaluated, QuantumSymbol, Scope
|
83
84
|
from classiq.model_expansions.scope_initialization import (
|
85
|
+
add_constants_to_scope,
|
84
86
|
add_entry_point_params_to_scope,
|
85
87
|
get_main_renamer,
|
86
88
|
init_top_level_scope,
|
@@ -107,8 +109,9 @@ class Interpreter:
|
|
107
109
|
self._is_frontend = is_frontend
|
108
110
|
self._model = model
|
109
111
|
self._current_scope = Scope()
|
110
|
-
self.
|
111
|
-
self.
|
112
|
+
self._top_level_scope = self._current_scope
|
113
|
+
self._builder = OperationBuilder(self._top_level_scope)
|
114
|
+
self._expanded_functions: dict[str, NativeFunctionDefinition] = {}
|
112
115
|
self._propagated_var_stack = PropagatedVarStack(
|
113
116
|
self._current_scope, self._builder
|
114
117
|
)
|
@@ -119,10 +122,11 @@ class Interpreter:
|
|
119
122
|
generative_functions = []
|
120
123
|
self._generative_functions = generative_functions
|
121
124
|
init_top_level_scope(model, generative_functions, self._current_scope)
|
122
|
-
|
125
|
+
self._expanded_functions_compilation_metadata: dict[
|
126
|
+
str, CompilationMetadata
|
127
|
+
] = dict()
|
123
128
|
self._counted_name_allocator = CountedNameAllocator()
|
124
129
|
self._error_manager: ErrorManager = ErrorManager()
|
125
|
-
self._synthesized_separately_blocks: dict[str, BlockFunctionInfo] = {}
|
126
130
|
|
127
131
|
@contextmanager
|
128
132
|
def _scope_guard(self, scope: Scope) -> Iterator[None]:
|
@@ -153,14 +157,13 @@ class Interpreter:
|
|
153
157
|
main_closure.positional_arg_declarations, main_closure
|
154
158
|
)
|
155
159
|
context = self._expand_operation(main_closure)
|
156
|
-
self._expanded_functions.
|
160
|
+
self._expanded_functions[main_closure.closure_id] = (
|
157
161
|
self._builder.create_definition(cast(FunctionContext, context))
|
158
162
|
)
|
159
163
|
|
160
|
-
def expand(self) ->
|
164
|
+
def expand(self) -> Model:
|
161
165
|
try:
|
162
166
|
with self._error_manager.call("main"):
|
163
|
-
self._synthesized_separately_blocks = {}
|
164
167
|
self._expand_main_func()
|
165
168
|
except Exception as e:
|
166
169
|
if isinstance(e, ClassiqInternalExpansionError) or debug_mode.get():
|
@@ -172,20 +175,18 @@ class Interpreter:
|
|
172
175
|
finally:
|
173
176
|
self._error_manager.report_errors(ClassiqExpansionError)
|
174
177
|
|
175
|
-
return (
|
176
|
-
|
177
|
-
|
178
|
-
|
179
|
-
|
180
|
-
|
181
|
-
|
182
|
-
|
183
|
-
|
184
|
-
|
185
|
-
|
186
|
-
|
187
|
-
),
|
188
|
-
self._synthesized_separately_blocks,
|
178
|
+
return Model(
|
179
|
+
constraints=self._model.constraints,
|
180
|
+
preferences=self._model.preferences,
|
181
|
+
classical_execution_code=self._model.classical_execution_code,
|
182
|
+
execution_preferences=self._model.execution_preferences,
|
183
|
+
functions=list(self._expanded_functions.values()),
|
184
|
+
constants=self._model.constants,
|
185
|
+
enums=self._model.enums,
|
186
|
+
types=self._model.types,
|
187
|
+
qstructs=self._model.qstructs,
|
188
|
+
debug_info=self._model.debug_info,
|
189
|
+
functions_compilation_metadata=self._expanded_functions_compilation_metadata,
|
189
190
|
)
|
190
191
|
|
191
192
|
@singledispatchmethod
|
@@ -346,9 +347,8 @@ class Interpreter:
|
|
346
347
|
|
347
348
|
def _expand_operation(self, operation: Closure) -> OperationContext:
|
348
349
|
with self._builder.operation_context(operation) as context:
|
349
|
-
if (
|
350
|
-
|
351
|
-
and operation.synthesis_data.should_synthesize_separately
|
350
|
+
if isinstance(operation, FunctionClosure) and (
|
351
|
+
self._expanded_functions.get(operation.closure_id) is not None
|
352
352
|
):
|
353
353
|
pass
|
354
354
|
elif isinstance(operation, FunctionClosure) and operation.name == "permute":
|
@@ -385,5 +385,8 @@ class Interpreter:
|
|
385
385
|
return (
|
386
386
|
self._model.functions
|
387
387
|
+ [gen_func.func_decl for gen_func in self._generative_functions]
|
388
|
-
+ self._expanded_functions
|
388
|
+
+ list(self._expanded_functions.values())
|
389
389
|
)
|
390
|
+
|
391
|
+
def add_constant(self, constant: Constant) -> None:
|
392
|
+
add_constants_to_scope([constant], self._top_level_scope)
|
@@ -9,6 +9,7 @@ from classiq.interface.exceptions import (
|
|
9
9
|
from classiq.interface.generator.compiler_keywords import INPLACE_ARITH_AUX_VAR_PREFIX
|
10
10
|
from classiq.interface.generator.expressions.expression import Expression
|
11
11
|
from classiq.interface.generator.expressions.expression_types import ExpressionValue
|
12
|
+
from classiq.interface.generator.expressions.qmod_qarray_proxy import QmodQArrayProxy
|
12
13
|
from classiq.interface.generator.expressions.qmod_qscalar_proxy import QmodQNumProxy
|
13
14
|
from classiq.interface.generator.expressions.qmod_sized_proxy import QmodSizedProxy
|
14
15
|
from classiq.interface.generator.functions.builtins.internal_operators import (
|
@@ -16,18 +17,24 @@ from classiq.interface.generator.functions.builtins.internal_operators import (
|
|
16
17
|
)
|
17
18
|
from classiq.interface.model.bind_operation import BindOperation
|
18
19
|
from classiq.interface.model.control import Control
|
19
|
-
from classiq.interface.model.handle_binding import
|
20
|
+
from classiq.interface.model.handle_binding import HandleBinding
|
20
21
|
from classiq.interface.model.quantum_expressions.arithmetic_operation import (
|
21
22
|
ArithmeticOperation,
|
22
23
|
ArithmeticOperationKind,
|
23
24
|
)
|
24
|
-
from classiq.interface.model.
|
25
|
+
from classiq.interface.model.quantum_function_call import QuantumFunctionCall
|
26
|
+
from classiq.interface.model.quantum_type import (
|
27
|
+
QuantumBit,
|
28
|
+
QuantumBitvector,
|
29
|
+
QuantumType,
|
30
|
+
)
|
25
31
|
from classiq.interface.model.statement_block import ConcreteQuantumStatement
|
26
32
|
from classiq.interface.model.variable_declaration_statement import (
|
27
33
|
VariableDeclarationStatement,
|
28
34
|
)
|
29
35
|
from classiq.interface.model.within_apply_operation import WithinApply
|
30
36
|
|
37
|
+
from classiq.model_expansions.capturing.mangling_utils import ARRAY_CAST_SUFFIX
|
31
38
|
from classiq.model_expansions.capturing.propagated_var_stack import (
|
32
39
|
validate_args_are_not_propagated,
|
33
40
|
)
|
@@ -40,39 +47,71 @@ from classiq.model_expansions.quantum_operations.expression_operation import (
|
|
40
47
|
ExpressionOperationEmitter,
|
41
48
|
)
|
42
49
|
from classiq.model_expansions.scope import Scope
|
43
|
-
|
44
|
-
ARRAY_CAST_SUFFIX = HANDLE_ID_SEPARATOR + "array_cast"
|
50
|
+
from classiq.qmod.builtins.functions.standard_gates import X
|
45
51
|
|
46
52
|
|
47
53
|
class ControlEmitter(ExpressionOperationEmitter[Control]):
|
48
54
|
def emit(self, control: Control, /) -> None:
|
49
55
|
condition = self._evaluate_op_expression(control)
|
50
|
-
control = control.model_copy(update=dict(expression=condition))
|
51
56
|
|
52
57
|
arrays_with_subscript = self._get_symbols_to_split(condition)
|
53
58
|
if len(arrays_with_subscript) > 0:
|
59
|
+
if control.is_generative():
|
60
|
+
with self._propagated_var_stack.capture_variables(control):
|
61
|
+
control = self._expand_generative_control(control)
|
54
62
|
self._emit_with_split(control, condition, arrays_with_subscript)
|
55
63
|
return
|
56
64
|
|
65
|
+
control = self._evaluate_types_in_expression(control, condition)
|
57
66
|
condition_val = condition.value.value
|
58
67
|
if isinstance(condition_val, QmodSizedProxy):
|
59
|
-
|
60
|
-
|
61
|
-
|
68
|
+
if control.else_block is None:
|
69
|
+
self._validate_canonical_condition(condition_val)
|
70
|
+
self._emit_canonical_control(control)
|
71
|
+
return
|
72
|
+
else:
|
73
|
+
self._interpreter.emit_statement(
|
74
|
+
control.model_copy(
|
75
|
+
update=dict(
|
76
|
+
expression=self._uncanonize_condition(condition_val)
|
77
|
+
)
|
78
|
+
)
|
79
|
+
)
|
80
|
+
return
|
62
81
|
|
63
|
-
self._validate_condition(
|
82
|
+
self._validate_condition(control)
|
64
83
|
self._emit_with_boolean(control)
|
65
84
|
|
85
|
+
def _uncanonize_condition(self, condition_val: QmodSizedProxy) -> Expression:
|
86
|
+
lhs = (
|
87
|
+
" & ".join(
|
88
|
+
f"{condition_val.handle}[{idx}]" for idx in range(condition_val.size)
|
89
|
+
)
|
90
|
+
if isinstance(condition_val, QmodQArrayProxy)
|
91
|
+
else condition_val.handle
|
92
|
+
)
|
93
|
+
return Expression(expr=f"{lhs} == 1")
|
94
|
+
|
95
|
+
def _expand_generative_control(self, control: Control) -> Control:
|
96
|
+
block_names = ["body"]
|
97
|
+
if control.has_generative_block("else_block"):
|
98
|
+
block_names += ["else_block"]
|
99
|
+
context = self._register_generative_context(
|
100
|
+
control, CONTROL_OPERATOR_NAME, block_names
|
101
|
+
)
|
102
|
+
new_blocks = {"body": context.statements("body")}
|
103
|
+
if "else_block" in block_names:
|
104
|
+
new_blocks["else_block"] = context.statements("else_block")
|
105
|
+
return control.model_copy(update=new_blocks)
|
106
|
+
|
66
107
|
def _emit_canonical_control(self, control: Control) -> None:
|
67
108
|
# canonical means control(q, body) where q is a single quantum variable
|
68
|
-
control = self._evaluate_types_in_expression(control, control.expression)
|
69
109
|
with self._propagated_var_stack.capture_variables(control):
|
70
110
|
self._emit_propagated(control)
|
71
111
|
|
72
112
|
def _emit_propagated(self, control: Control) -> None:
|
73
113
|
if control.is_generative():
|
74
|
-
|
75
|
-
control = control.model_copy(update={"body": context.statements("body")})
|
114
|
+
control = self._expand_generative_control(control)
|
76
115
|
|
77
116
|
if self._should_wrap_control(control):
|
78
117
|
self._emit_wrapped(control)
|
@@ -98,7 +137,7 @@ class ControlEmitter(ExpressionOperationEmitter[Control]):
|
|
98
137
|
context = self._expand_operation(control_operation)
|
99
138
|
validate_args_are_not_propagated(
|
100
139
|
control.var_handles,
|
101
|
-
self._propagated_var_stack.get_propagated_variables(),
|
140
|
+
self._propagated_var_stack.get_propagated_variables(flatten=False),
|
102
141
|
)
|
103
142
|
self._update_control_state(control)
|
104
143
|
self._builder.emit_statement(
|
@@ -111,7 +150,7 @@ class ControlEmitter(ExpressionOperationEmitter[Control]):
|
|
111
150
|
)
|
112
151
|
validate_args_are_not_propagated(
|
113
152
|
control.var_handles,
|
114
|
-
self._propagated_var_stack.get_propagated_variables(),
|
153
|
+
self._propagated_var_stack.get_propagated_variables(flatten=False),
|
115
154
|
)
|
116
155
|
self._update_control_state(control)
|
117
156
|
self._builder.emit_statement(
|
@@ -129,9 +168,10 @@ class ControlEmitter(ExpressionOperationEmitter[Control]):
|
|
129
168
|
condition_val = control.expression.value.value
|
130
169
|
if self._is_simple_equality(condition_val):
|
131
170
|
ctrl, ctrl_state = resolve_num_condition(condition_val)
|
132
|
-
|
133
|
-
|
134
|
-
|
171
|
+
if control.else_block is None or ctrl.size == 1:
|
172
|
+
self._emit_with_x_gates(control, ctrl, ctrl_state)
|
173
|
+
return
|
174
|
+
self._emit_with_arithmetic(control)
|
135
175
|
|
136
176
|
@staticmethod
|
137
177
|
def _is_simple_equality(condition_val: ExpressionValue) -> TypeGuard[Equality]:
|
@@ -151,13 +191,38 @@ class ControlEmitter(ExpressionOperationEmitter[Control]):
|
|
151
191
|
|
152
192
|
def _create_canonical_control_op(
|
153
193
|
self, control: Control, handle_name: str
|
154
|
-
) ->
|
194
|
+
) -> list[ConcreteQuantumStatement]:
|
155
195
|
handle_expr = self._interpreter.evaluate(Expression(expr=handle_name)).emit()
|
156
|
-
|
196
|
+
control_then = control.model_copy(
|
197
|
+
update=dict(expression=handle_expr, else_block=None)
|
198
|
+
)
|
199
|
+
if control.else_block is None:
|
200
|
+
return [control_then]
|
201
|
+
else_compute_call = QuantumFunctionCall(
|
202
|
+
function="X", positional_args=[HandleBinding(name=handle_name)]
|
203
|
+
)
|
204
|
+
else_compute_call.set_func_decl(X.func_decl)
|
205
|
+
control_else_inner = control.model_copy(
|
206
|
+
update=dict(
|
207
|
+
expression=handle_expr, body=control.else_block, else_block=None
|
208
|
+
),
|
209
|
+
deep=True,
|
210
|
+
)
|
211
|
+
control_else = WithinApply(
|
212
|
+
compute=[else_compute_call],
|
213
|
+
action=[control_else_inner],
|
214
|
+
)
|
215
|
+
if control_else_inner.is_generative():
|
216
|
+
control_then.remove_generative_block("else_block")
|
217
|
+
control_else_inner.set_generative_block(
|
218
|
+
"body", control_else_inner.get_generative_block("else_block")
|
219
|
+
)
|
220
|
+
control_else_inner.remove_generative_block("else_block")
|
221
|
+
return [control_then, control_else]
|
157
222
|
|
158
|
-
def
|
223
|
+
def _control_with_x_gates(
|
159
224
|
self, control: Control, ctrl: QmodSizedProxy, ctrl_state: str
|
160
|
-
) ->
|
225
|
+
) -> ConcreteQuantumStatement:
|
161
226
|
compute_op: list[ConcreteQuantumStatement] = []
|
162
227
|
|
163
228
|
x_gate_value = self._get_x_gate_value(ctrl_state)
|
@@ -175,12 +240,19 @@ class ControlEmitter(ExpressionOperationEmitter[Control]):
|
|
175
240
|
cast_decl, bind_op = self._get_array_cast_ops(ctrl)
|
176
241
|
self._interpreter.emit_statement(cast_decl)
|
177
242
|
compute_op.append(bind_op)
|
178
|
-
|
243
|
+
control_ops = self._create_canonical_control_op(
|
244
|
+
control, str(cast_decl.name)
|
245
|
+
)
|
179
246
|
else:
|
180
|
-
|
247
|
+
control_ops = self._create_canonical_control_op(control, str(ctrl.handle))
|
248
|
+
|
249
|
+
return WithinApply(compute=compute_op, action=control_ops)
|
181
250
|
|
251
|
+
def _emit_with_x_gates(
|
252
|
+
self, control: Control, ctrl: QmodSizedProxy, ctrl_state: str
|
253
|
+
) -> None:
|
182
254
|
self._interpreter.emit_statement(
|
183
|
-
|
255
|
+
self._control_with_x_gates(control, ctrl, ctrl_state)
|
184
256
|
)
|
185
257
|
|
186
258
|
@staticmethod
|
@@ -217,20 +289,33 @@ class ControlEmitter(ExpressionOperationEmitter[Control]):
|
|
217
289
|
self._interpreter.emit_statement(
|
218
290
|
WithinApply(
|
219
291
|
compute=[arith_expression],
|
220
|
-
action=
|
292
|
+
action=self._create_canonical_control_op(control, aux_var),
|
221
293
|
)
|
222
294
|
)
|
223
295
|
|
224
|
-
|
225
|
-
|
226
|
-
if not
|
227
|
-
|
296
|
+
def _validate_condition(self, control: Control) -> None:
|
297
|
+
condition_value = control.expression.value.value
|
298
|
+
if not (
|
299
|
+
isinstance(condition_value, Boolean)
|
300
|
+
or self._all_vars_boolean(control)
|
301
|
+
and self._is_res_boolean(control)
|
302
|
+
):
|
303
|
+
raise ClassiqExpansionError(_condition_err_msg(condition_value))
|
228
304
|
|
229
305
|
@staticmethod
|
230
306
|
def _validate_canonical_condition(condition_val: ExpressionValue) -> None:
|
231
307
|
if isinstance(condition_val, QmodQNumProxy):
|
232
308
|
raise ClassiqExpansionError(_condition_err_msg(condition_val))
|
233
309
|
|
310
|
+
def _get_updated_op_split_symbols(
|
311
|
+
self, op: Control, symbol_mapping: dict[HandleBinding, tuple[str, QuantumType]]
|
312
|
+
) -> Control:
|
313
|
+
new_body = self._rewrite(op.body, symbol_mapping)
|
314
|
+
new_else = None
|
315
|
+
if op.else_block is not None:
|
316
|
+
new_else = self._rewrite(op.else_block, symbol_mapping)
|
317
|
+
return op.model_copy(update=dict(body=new_body, else_block=new_else))
|
318
|
+
|
234
319
|
|
235
320
|
def _condition_err_msg(condition_val: ExpressionValue) -> str:
|
236
321
|
return (
|
@@ -70,7 +70,12 @@ class Emitter(Generic[QuantumStatementT]):
|
|
70
70
|
|
71
71
|
self._scope_guard = self._interpreter._scope_guard
|
72
72
|
self._machine_precision = self._interpreter._model.preferences.machine_precision
|
73
|
-
|
73
|
+
self._expanded_functions_compilation_metadata = (
|
74
|
+
self._interpreter._expanded_functions_compilation_metadata
|
75
|
+
)
|
76
|
+
self._functions_compilation_metadata = (
|
77
|
+
self._interpreter._model.functions_compilation_metadata
|
78
|
+
)
|
74
79
|
self._generative_contexts: dict[str, OperationContext] = {}
|
75
80
|
|
76
81
|
@abstractmethod
|
@@ -100,7 +105,11 @@ class Emitter(Generic[QuantumStatementT]):
|
|
100
105
|
return self._interpreter._current_scope
|
101
106
|
|
102
107
|
@property
|
103
|
-
def
|
108
|
+
def _top_level_scope(self) -> Scope:
|
109
|
+
return self._interpreter._top_level_scope
|
110
|
+
|
111
|
+
@property
|
112
|
+
def _expanded_functions(self) -> dict[str, NativeFunctionDefinition]:
|
104
113
|
return self._interpreter._expanded_functions
|
105
114
|
|
106
115
|
@property
|
@@ -137,23 +146,38 @@ class Emitter(Generic[QuantumStatementT]):
|
|
137
146
|
)
|
138
147
|
new_positional_arg_decls = new_declaration.positional_arg_declarations
|
139
148
|
is_atomic = function.is_atomic
|
140
|
-
|
149
|
+
new_function_name = function.name
|
150
|
+
if not is_atomic: # perform monomorphization per interpreted parameters set
|
141
151
|
self._add_params_to_scope(
|
142
152
|
new_positional_arg_decls, evaluated_args, function
|
143
153
|
)
|
144
154
|
context = self._expand_operation(
|
145
155
|
function.with_new_declaration(new_declaration)
|
146
156
|
)
|
147
|
-
|
148
|
-
|
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
|
149
170
|
)
|
171
|
+
if compilation_metadata is not None:
|
172
|
+
self._expanded_functions_compilation_metadata[new_function_name] = (
|
173
|
+
compilation_metadata
|
174
|
+
)
|
175
|
+
|
150
176
|
new_positional_args = self._get_new_positional_args(
|
151
177
|
evaluated_args, is_atomic, new_positional_arg_decls
|
152
178
|
)
|
153
179
|
new_call = QuantumFunctionCall(
|
154
|
-
function=
|
155
|
-
new_declaration.name if is_atomic else self._expanded_functions[-1].name
|
156
|
-
),
|
180
|
+
function=new_function_name,
|
157
181
|
positional_args=new_positional_args,
|
158
182
|
)
|
159
183
|
is_allocate_or_free = (
|
@@ -178,8 +202,7 @@ class Emitter(Generic[QuantumStatementT]):
|
|
178
202
|
is_allocate_or_free=is_allocate_or_free,
|
179
203
|
port_to_passed_variable_map=port_to_passed_variable_map,
|
180
204
|
)
|
181
|
-
|
182
|
-
new_call.set_func_decl(new_declaration)
|
205
|
+
new_call.set_func_decl(new_declaration)
|
183
206
|
return new_call
|
184
207
|
|
185
208
|
@staticmethod
|
@@ -220,7 +243,9 @@ class Emitter(Generic[QuantumStatementT]):
|
|
220
243
|
arg.emit() for arg in evaluated_args if isinstance(arg.value, QuantumSymbol)
|
221
244
|
]
|
222
245
|
|
223
|
-
propagated_variables = self._propagated_var_stack.get_propagated_variables(
|
246
|
+
propagated_variables = self._propagated_var_stack.get_propagated_variables(
|
247
|
+
flatten=True
|
248
|
+
)
|
224
249
|
validate_args_are_not_propagated(positional_args, propagated_variables)
|
225
250
|
positional_args.extend(propagated_variables)
|
226
251
|
|
@@ -279,6 +304,7 @@ class Emitter(Generic[QuantumStatementT]):
|
|
279
304
|
)
|
280
305
|
context = self._interpreter._expand_operation(gen_closure)
|
281
306
|
self._generative_contexts[context_name] = context
|
307
|
+
op.clear_generative_blocks()
|
282
308
|
return context
|
283
309
|
|
284
310
|
def _evaluate_expression(self, expression: Expression) -> Expression:
|