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