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