classiq 0.64.0__py3-none-any.whl → 0.65.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/_internals/api_wrapper.py +30 -0
- classiq/applications/chemistry/chemistry_model_constructor.py +8 -9
- classiq/applications/combinatorial_optimization/combinatorial_optimization_model_constructor.py +4 -6
- classiq/applications/combinatorial_optimization/combinatorial_problem.py +2 -5
- classiq/applications/finance/finance_model_constructor.py +7 -12
- classiq/applications/grover/grover_model_constructor.py +4 -6
- classiq/applications/qsvm/qsvm_model_constructor.py +6 -4
- classiq/execution/execution_session.py +14 -13
- classiq/interface/_version.py +1 -1
- classiq/interface/backend/backend_preferences.py +1 -9
- classiq/interface/generator/expressions/qmod_qarray_proxy.py +11 -13
- classiq/interface/generator/functions/type_name.py +6 -0
- classiq/interface/model/allocate.py +16 -0
- classiq/interface/model/quantum_type.py +26 -0
- classiq/interface/model/statement_block.py +2 -0
- classiq/interface/server/routes.py +1 -0
- classiq/model_expansions/evaluators/quantum_type_utils.py +10 -0
- classiq/model_expansions/function_builder.py +35 -11
- classiq/model_expansions/generative_functions.py +6 -4
- classiq/model_expansions/interpreters/base_interpreter.py +37 -138
- classiq/model_expansions/interpreters/frontend_generative_interpreter.py +28 -0
- classiq/model_expansions/interpreters/generative_interpreter.py +144 -3
- classiq/model_expansions/quantum_operations/call_emitter.py +43 -91
- classiq/model_expansions/quantum_operations/declarative_call_emitter.py +87 -0
- classiq/model_expansions/quantum_operations/emitter.py +5 -0
- classiq/model_expansions/quantum_operations/quantum_function_call.py +9 -0
- classiq/model_expansions/quantum_operations/shallow_emitter.py +20 -1
- classiq/model_expansions/scope.py +15 -15
- classiq/model_expansions/scope_initialization.py +3 -5
- classiq/open_library/functions/discrete_sine_cosine_transform.py +8 -2
- classiq/open_library/functions/grover.py +1 -1
- classiq/open_library/functions/modular_exponentiation.py +8 -2
- classiq/open_library/functions/state_preparation.py +23 -13
- classiq/open_library/functions/swap_test.py +1 -2
- classiq/open_library/functions/variational.py +1 -2
- classiq/qmod/builtins/__init__.py +1 -1
- classiq/qmod/builtins/operations.py +51 -0
- classiq/qmod/native/pretty_printer.py +9 -1
- classiq/qmod/pretty_print/pretty_printer.py +12 -1
- classiq/qmod/qmod_variable.py +38 -38
- classiq/qmod/quantum_function.py +4 -4
- classiq/qmod/semantics/annotation/__init__.py +0 -0
- classiq/qmod/semantics/annotation/call_annotation.py +92 -0
- classiq/qmod/semantics/lambdas.py +25 -0
- classiq/qmod/semantics/static_semantics_visitor.py +8 -46
- classiq/qmod/utilities.py +16 -0
- {classiq-0.64.0.dist-info → classiq-0.65.1.dist-info}/METADATA +1 -1
- {classiq-0.64.0.dist-info → classiq-0.65.1.dist-info}/RECORD +50 -45
- classiq/qmod/semantics/annotation.py +0 -36
- /classiq/qmod/semantics/{qstruct_annotator.py → annotation/qstruct_annotator.py} +0 -0
- {classiq-0.64.0.dist-info → classiq-0.65.1.dist-info}/WHEEL +0 -0
@@ -1,3 +1,4 @@
|
|
1
|
+
import ast
|
1
2
|
from abc import abstractmethod
|
2
3
|
from collections import defaultdict
|
3
4
|
from collections.abc import Sequence
|
@@ -5,8 +6,7 @@ from contextlib import nullcontext
|
|
5
6
|
from functools import singledispatchmethod
|
6
7
|
from typing import Any, Optional, cast
|
7
8
|
|
8
|
-
import
|
9
|
-
from numpy.random import permutation
|
9
|
+
import sympy
|
10
10
|
from pydantic import ValidationError
|
11
11
|
|
12
12
|
from classiq.interface.exceptions import (
|
@@ -25,11 +25,7 @@ from classiq.interface.model.handle_binding import (
|
|
25
25
|
)
|
26
26
|
from classiq.interface.model.model import MAIN_FUNCTION_NAME, Model
|
27
27
|
from classiq.interface.model.native_function_definition import NativeFunctionDefinition
|
28
|
-
from classiq.interface.model.quantum_function_call import (
|
29
|
-
QuantumFunctionCall,
|
30
|
-
)
|
31
28
|
from classiq.interface.model.quantum_function_declaration import (
|
32
|
-
NamedParamsQuantumFunctionDeclaration,
|
33
29
|
QuantumFunctionDeclaration,
|
34
30
|
)
|
35
31
|
from classiq.interface.model.quantum_lambda_function import (
|
@@ -41,8 +37,6 @@ from classiq.interface.model.quantum_statement import QuantumStatement
|
|
41
37
|
from classiq.model_expansions.closure import (
|
42
38
|
Closure,
|
43
39
|
FunctionClosure,
|
44
|
-
GenerativeClosure,
|
45
|
-
GenerativeFunctionClosure,
|
46
40
|
)
|
47
41
|
from classiq.model_expansions.debug_flag import debug_mode
|
48
42
|
from classiq.model_expansions.evaluators.classical_expression import (
|
@@ -54,32 +48,24 @@ from classiq.model_expansions.function_builder import (
|
|
54
48
|
OperationBuilder,
|
55
49
|
OperationContext,
|
56
50
|
)
|
57
|
-
from classiq.model_expansions.generative_functions import emit_generative_statements
|
58
51
|
from classiq.model_expansions.scope import Evaluated, QuantumSymbol, Scope
|
59
52
|
from classiq.model_expansions.scope_initialization import (
|
60
53
|
add_constants_to_scope,
|
61
54
|
add_entry_point_params_to_scope,
|
62
|
-
add_functions_to_scope,
|
63
|
-
add_generative_functions_to_scope,
|
64
55
|
get_main_renamer,
|
65
56
|
init_builtin_types,
|
66
57
|
init_top_level_scope,
|
67
58
|
)
|
68
59
|
from classiq.model_expansions.utils.counted_name_allocator import CountedNameAllocator
|
60
|
+
from classiq.model_expansions.visitors.variable_references import VarRefCollector
|
69
61
|
from classiq.qmod.builtins.enums import BUILTIN_ENUM_DECLARATIONS
|
70
|
-
from classiq.qmod.builtins.functions import permute
|
71
62
|
from classiq.qmod.builtins.structs import BUILTIN_STRUCT_DECLARATIONS
|
72
|
-
from classiq.qmod.model_state_container import QMODULE
|
73
|
-
from classiq.qmod.quantum_function import GenerativeQFunc
|
63
|
+
from classiq.qmod.model_state_container import QMODULE
|
74
64
|
from classiq.qmod.semantics.error_manager import ErrorManager
|
75
65
|
|
76
66
|
|
77
67
|
class BaseInterpreter:
|
78
|
-
def __init__(
|
79
|
-
self,
|
80
|
-
model: Model,
|
81
|
-
generative_functions: Optional[list[GenerativeQFunc]] = None,
|
82
|
-
) -> None:
|
68
|
+
def __init__(self, model: Model) -> None:
|
83
69
|
self._model = model
|
84
70
|
self._top_level_scope = Scope()
|
85
71
|
self._counted_name_allocator = CountedNameAllocator()
|
@@ -89,7 +75,7 @@ class BaseInterpreter:
|
|
89
75
|
self._expanded_functions: dict[str, NativeFunctionDefinition] = {}
|
90
76
|
|
91
77
|
init_builtin_types()
|
92
|
-
init_top_level_scope(model,
|
78
|
+
init_top_level_scope(model, self._top_level_scope)
|
93
79
|
self._functions_compilation_metadata: dict[str, CompilationMetadata] = dict(
|
94
80
|
self._model.functions_compilation_metadata
|
95
81
|
)
|
@@ -99,33 +85,13 @@ class BaseInterpreter:
|
|
99
85
|
self._counted_name_allocator = CountedNameAllocator()
|
100
86
|
self._error_manager: ErrorManager = ErrorManager()
|
101
87
|
|
102
|
-
@property
|
103
|
-
def is_shallow(self) -> bool:
|
104
|
-
return False
|
105
|
-
|
106
88
|
def get_main_renamer(self) -> Optional[ExpressionRenamer]:
|
107
89
|
return get_main_renamer(self._get_function_declarations())
|
108
90
|
|
109
91
|
def _expand_main_func(self) -> None:
|
110
|
-
|
111
|
-
|
112
|
-
if isinstance(main_func, GenerativeFunctionClosure):
|
113
|
-
closure_constructor = GenerativeFunctionClosure
|
114
|
-
extra_args = {
|
115
|
-
"generative_blocks": {"body": main_func.generative_blocks["body"]}
|
116
|
-
}
|
117
|
-
else:
|
118
|
-
closure_constructor = FunctionClosure
|
119
|
-
extra_args = {"body": main_func.body}
|
120
|
-
main_closure = closure_constructor.create(
|
121
|
-
name=main_func.name,
|
122
|
-
positional_arg_declarations=main_func.positional_arg_declarations,
|
123
|
-
scope=Scope(parent=self._top_level_scope),
|
124
|
-
expr_renamer=self.get_main_renamer(),
|
125
|
-
_depth=0,
|
126
|
-
**extra_args,
|
92
|
+
main_closure = self._get_main_closure(
|
93
|
+
self._top_level_scope[MAIN_FUNCTION_NAME].value
|
127
94
|
)
|
128
|
-
|
129
95
|
add_entry_point_params_to_scope(
|
130
96
|
main_closure.positional_arg_declarations, main_closure
|
131
97
|
)
|
@@ -134,6 +100,16 @@ class BaseInterpreter:
|
|
134
100
|
self._builder.create_definition(cast(FunctionContext, context))
|
135
101
|
)
|
136
102
|
|
103
|
+
def _get_main_closure(self, main_func: FunctionClosure) -> FunctionClosure:
|
104
|
+
return FunctionClosure.create(
|
105
|
+
name=main_func.name,
|
106
|
+
positional_arg_declarations=main_func.positional_arg_declarations,
|
107
|
+
scope=Scope(parent=self._top_level_scope),
|
108
|
+
expr_renamer=self.get_main_renamer(),
|
109
|
+
_depth=0,
|
110
|
+
body=main_func.body,
|
111
|
+
)
|
112
|
+
|
137
113
|
def expand(self) -> Model:
|
138
114
|
try:
|
139
115
|
with self._error_manager.call("main"):
|
@@ -178,49 +154,28 @@ class BaseInterpreter:
|
|
178
154
|
|
179
155
|
@evaluate.register
|
180
156
|
def evaluate_classical_expression(self, expression: Expression) -> Evaluated:
|
181
|
-
|
157
|
+
expr = evaluate_classical_expression(expression, self._builder.current_scope)
|
158
|
+
if not isinstance(expr.value, sympy.Basic):
|
159
|
+
return expr
|
160
|
+
vrc = VarRefCollector(ignore_duplicated_handles=True)
|
161
|
+
vrc.visit(ast.parse(str(expr.value)))
|
162
|
+
for handle in vrc.var_handles:
|
163
|
+
if handle.name in self._builder.current_scope and isinstance(
|
164
|
+
self._builder.current_scope[handle.name], QuantumSymbol
|
165
|
+
):
|
166
|
+
self.evaluate(handle)
|
167
|
+
return expr
|
182
168
|
|
183
169
|
@evaluate.register
|
184
170
|
def evaluate_identifier(self, identifier: str) -> Evaluated:
|
185
171
|
return self._builder.current_scope[identifier]
|
186
172
|
|
187
173
|
@evaluate.register
|
188
|
-
def
|
189
|
-
|
190
|
-
param.rename(function.pos_rename_params[idx])
|
191
|
-
for idx, param in enumerate(function.func_decl.positional_arg_declarations)
|
192
|
-
]
|
193
|
-
func_decl = NamedParamsQuantumFunctionDeclaration(
|
194
|
-
name=self._counted_name_allocator.allocate(
|
195
|
-
function.func_decl.name or "<lambda>"
|
196
|
-
),
|
197
|
-
positional_arg_declarations=renamed_params,
|
198
|
-
)
|
199
|
-
|
200
|
-
closure_class: type[FunctionClosure]
|
201
|
-
extra_args: dict[str, Any]
|
202
|
-
if function.is_generative():
|
203
|
-
closure_class = GenerativeFunctionClosure
|
204
|
-
extra_args = {
|
205
|
-
"generative_blocks": {
|
206
|
-
"body": GenerativeQFunc(function.py_callable, func_decl),
|
207
|
-
}
|
208
|
-
}
|
209
|
-
else:
|
210
|
-
closure_class = FunctionClosure
|
211
|
-
extra_args = {}
|
174
|
+
def _evaluate_lambda(self, function: QuantumLambdaFunction) -> Evaluated:
|
175
|
+
return self.evaluate_lambda(function)
|
212
176
|
|
213
|
-
|
214
|
-
|
215
|
-
name=func_decl.name,
|
216
|
-
positional_arg_declarations=func_decl.positional_arg_declarations,
|
217
|
-
body=function.body,
|
218
|
-
scope=Scope(parent=self._builder.current_scope),
|
219
|
-
is_lambda=True,
|
220
|
-
**extra_args,
|
221
|
-
),
|
222
|
-
defining_function=self._builder.current_function,
|
223
|
-
)
|
177
|
+
def evaluate_lambda(self, function: QuantumLambdaFunction) -> Evaluated:
|
178
|
+
raise NotImplementedError
|
224
179
|
|
225
180
|
@evaluate.register
|
226
181
|
def evaluate_handle_binding(self, handle_binding: HandleBinding) -> Evaluated:
|
@@ -285,34 +240,14 @@ class BaseInterpreter:
|
|
285
240
|
):
|
286
241
|
captured_vars = self._top_level_scope[func_def.name].value.captured_vars
|
287
242
|
operation.captured_vars.update(captured_vars)
|
288
|
-
elif isinstance(operation, FunctionClosure) and operation.name == "permute":
|
289
|
-
# special expansion since permute is generative
|
290
|
-
self._expand_permute()
|
291
|
-
elif isinstance(operation, GenerativeClosure):
|
292
|
-
args = [
|
293
|
-
self.evaluate(param.name)
|
294
|
-
for param in operation.positional_arg_declarations
|
295
|
-
]
|
296
|
-
emit_generative_statements(self, operation, args)
|
297
243
|
else:
|
298
|
-
|
299
|
-
self._expand_block(block_body, block)
|
244
|
+
self._expand_body(operation)
|
300
245
|
|
301
246
|
return context
|
302
247
|
|
303
|
-
def
|
304
|
-
|
305
|
-
|
306
|
-
calls: list[QuantumFunctionCall] = []
|
307
|
-
for function_index in functions_permutation:
|
308
|
-
permute_call = QuantumFunctionCall(
|
309
|
-
function=OperandIdentifier(
|
310
|
-
name="functions", index=Expression(expr=f"{function_index}")
|
311
|
-
)
|
312
|
-
)
|
313
|
-
permute_call.set_func_decl(permute.func_decl)
|
314
|
-
calls.append(permute_call)
|
315
|
-
self._expand_block(calls, "body")
|
248
|
+
def _expand_body(self, operation: Closure) -> None:
|
249
|
+
for block, block_body in operation.blocks.items():
|
250
|
+
self._expand_block(block_body, block)
|
316
251
|
|
317
252
|
def _get_function_declarations(self) -> Sequence[QuantumFunctionDeclaration]:
|
318
253
|
return [
|
@@ -326,39 +261,3 @@ class BaseInterpreter:
|
|
326
261
|
|
327
262
|
def add_constant(self, constant: Constant) -> None:
|
328
263
|
add_constants_to_scope([constant], self._top_level_scope)
|
329
|
-
|
330
|
-
def update_declarative_functions(
|
331
|
-
self,
|
332
|
-
functions: dict[str, NativeFunctionDefinition],
|
333
|
-
qmodule: ModelStateContainer,
|
334
|
-
) -> None:
|
335
|
-
add_functions_to_scope(list(functions.values()), self._top_level_scope)
|
336
|
-
for dec_func_name in functions:
|
337
|
-
if dec_func_name in qmodule.functions_compilation_metadata:
|
338
|
-
self._functions_compilation_metadata[dec_func_name] = (
|
339
|
-
qmodule.functions_compilation_metadata[dec_func_name]
|
340
|
-
)
|
341
|
-
|
342
|
-
def update_generative_functions(
|
343
|
-
self, generative_functions: dict[str, GenerativeQFunc]
|
344
|
-
) -> None:
|
345
|
-
add_generative_functions_to_scope(
|
346
|
-
list(generative_functions.values()), self._top_level_scope
|
347
|
-
)
|
348
|
-
for name, gen_func in generative_functions.items():
|
349
|
-
if gen_func.compilation_metadata is not None:
|
350
|
-
self._functions_compilation_metadata[name] = (
|
351
|
-
gen_func.compilation_metadata
|
352
|
-
)
|
353
|
-
|
354
|
-
def add_purely_declarative_function(self, function: FunctionClosure) -> None:
|
355
|
-
functions_to_add = [function.name] + QMODULE.function_dependencies[
|
356
|
-
function.name
|
357
|
-
]
|
358
|
-
for func in functions_to_add:
|
359
|
-
if func not in self._expanded_functions and func in QMODULE.native_defs:
|
360
|
-
self._expanded_functions[func] = QMODULE.native_defs[func]
|
361
|
-
if func in QMODULE.functions_compilation_metadata:
|
362
|
-
self._expanded_functions_compilation_metadata[func] = (
|
363
|
-
QMODULE.functions_compilation_metadata[func]
|
364
|
-
)
|
@@ -0,0 +1,28 @@
|
|
1
|
+
from classiq.interface.model.quantum_function_call import QuantumFunctionCall
|
2
|
+
|
3
|
+
from classiq.model_expansions.closure import FunctionClosure, GenerativeFunctionClosure
|
4
|
+
from classiq.model_expansions.interpreters.generative_interpreter import (
|
5
|
+
GenerativeInterpreter,
|
6
|
+
)
|
7
|
+
from classiq.model_expansions.quantum_operations.quantum_function_call import (
|
8
|
+
DeclarativeQuantumFunctionCallEmitter,
|
9
|
+
)
|
10
|
+
from classiq.model_expansions.scope import Scope
|
11
|
+
|
12
|
+
|
13
|
+
class FrontendGenerativeInterpreter(GenerativeInterpreter):
|
14
|
+
def emit_quantum_function_call(self, call: QuantumFunctionCall) -> None:
|
15
|
+
DeclarativeQuantumFunctionCallEmitter(self).emit(call)
|
16
|
+
|
17
|
+
def _get_main_closure(self, main_func: FunctionClosure) -> FunctionClosure:
|
18
|
+
if isinstance(main_func, GenerativeFunctionClosure):
|
19
|
+
return GenerativeFunctionClosure.create(
|
20
|
+
name=main_func.name,
|
21
|
+
positional_arg_declarations=main_func.positional_arg_declarations,
|
22
|
+
scope=Scope(parent=self._top_level_scope),
|
23
|
+
expr_renamer=self.get_main_renamer(),
|
24
|
+
_depth=0,
|
25
|
+
generative_blocks={"body": main_func.generative_blocks["body"]},
|
26
|
+
)
|
27
|
+
|
28
|
+
return super()._get_main_closure(main_func)
|
@@ -1,21 +1,36 @@
|
|
1
1
|
from functools import singledispatchmethod
|
2
|
+
from typing import Any
|
2
3
|
|
4
|
+
import numpy as np
|
5
|
+
from numpy.random import permutation
|
6
|
+
|
7
|
+
from classiq.interface.generator.expressions.expression import Expression
|
3
8
|
from classiq.interface.generator.functions.builtins.internal_operators import (
|
4
9
|
CONTROL_OPERATOR_NAME,
|
5
10
|
INVERT_OPERATOR_NAME,
|
6
11
|
WITHIN_APPLY_NAME,
|
7
12
|
)
|
13
|
+
from classiq.interface.model.allocate import Allocate
|
8
14
|
from classiq.interface.model.bind_operation import BindOperation
|
9
15
|
from classiq.interface.model.classical_if import ClassicalIf
|
10
16
|
from classiq.interface.model.control import Control
|
11
17
|
from classiq.interface.model.inplace_binary_operation import InplaceBinaryOperation
|
12
18
|
from classiq.interface.model.invert import Invert
|
19
|
+
from classiq.interface.model.model import Model
|
20
|
+
from classiq.interface.model.native_function_definition import NativeFunctionDefinition
|
13
21
|
from classiq.interface.model.phase_operation import PhaseOperation
|
14
22
|
from classiq.interface.model.power import Power
|
15
23
|
from classiq.interface.model.quantum_expressions.quantum_expression import (
|
16
24
|
QuantumAssignmentOperation,
|
17
25
|
)
|
18
26
|
from classiq.interface.model.quantum_function_call import QuantumFunctionCall
|
27
|
+
from classiq.interface.model.quantum_function_declaration import (
|
28
|
+
NamedParamsQuantumFunctionDeclaration,
|
29
|
+
)
|
30
|
+
from classiq.interface.model.quantum_lambda_function import (
|
31
|
+
OperandIdentifier,
|
32
|
+
QuantumLambdaFunction,
|
33
|
+
)
|
19
34
|
from classiq.interface.model.quantum_statement import QuantumStatement
|
20
35
|
from classiq.interface.model.repeat import Repeat
|
21
36
|
from classiq.interface.model.variable_declaration_statement import (
|
@@ -23,6 +38,13 @@ from classiq.interface.model.variable_declaration_statement import (
|
|
23
38
|
)
|
24
39
|
from classiq.interface.model.within_apply_operation import WithinApply
|
25
40
|
|
41
|
+
from classiq.model_expansions.closure import (
|
42
|
+
Closure,
|
43
|
+
FunctionClosure,
|
44
|
+
GenerativeClosure,
|
45
|
+
GenerativeFunctionClosure,
|
46
|
+
)
|
47
|
+
from classiq.model_expansions.generative_functions import emit_generative_statements
|
26
48
|
from classiq.model_expansions.interpreters.base_interpreter import BaseInterpreter
|
27
49
|
from classiq.model_expansions.quantum_operations import (
|
28
50
|
BindEmitter,
|
@@ -32,21 +54,77 @@ from classiq.model_expansions.quantum_operations import (
|
|
32
54
|
VariableDeclarationStatementEmitter,
|
33
55
|
)
|
34
56
|
from classiq.model_expansions.quantum_operations.shallow_emitter import ShallowEmitter
|
57
|
+
from classiq.model_expansions.scope import Evaluated, Scope
|
58
|
+
from classiq.model_expansions.scope_initialization import (
|
59
|
+
add_functions_to_scope,
|
60
|
+
add_generative_functions_to_scope,
|
61
|
+
)
|
62
|
+
from classiq.qmod.builtins.functions import permute
|
63
|
+
from classiq.qmod.model_state_container import QMODULE, ModelStateContainer
|
64
|
+
from classiq.qmod.quantum_function import GenerativeQFunc
|
35
65
|
|
36
66
|
|
37
67
|
class GenerativeInterpreter(BaseInterpreter):
|
38
|
-
|
39
|
-
|
40
|
-
|
68
|
+
def __init__(
|
69
|
+
self,
|
70
|
+
model: Model,
|
71
|
+
generative_functions: list[GenerativeQFunc],
|
72
|
+
) -> None:
|
73
|
+
super().__init__(model)
|
74
|
+
add_generative_functions_to_scope(generative_functions, self._top_level_scope)
|
75
|
+
|
76
|
+
def evaluate_lambda(self, function: QuantumLambdaFunction) -> Evaluated:
|
77
|
+
renamed_params = [
|
78
|
+
param.rename(function.pos_rename_params[idx])
|
79
|
+
for idx, param in enumerate(function.func_decl.positional_arg_declarations)
|
80
|
+
]
|
81
|
+
func_decl = NamedParamsQuantumFunctionDeclaration(
|
82
|
+
name=self._counted_name_allocator.allocate(
|
83
|
+
function.func_decl.name or "<lambda>"
|
84
|
+
),
|
85
|
+
positional_arg_declarations=renamed_params,
|
86
|
+
)
|
87
|
+
|
88
|
+
closure_class: type[FunctionClosure]
|
89
|
+
extra_args: dict[str, Any]
|
90
|
+
if function.is_generative():
|
91
|
+
closure_class = GenerativeFunctionClosure
|
92
|
+
extra_args = {
|
93
|
+
"generative_blocks": {
|
94
|
+
"body": GenerativeQFunc(function.py_callable, func_decl),
|
95
|
+
}
|
96
|
+
}
|
97
|
+
else:
|
98
|
+
closure_class = FunctionClosure
|
99
|
+
extra_args = {}
|
100
|
+
|
101
|
+
return Evaluated(
|
102
|
+
value=closure_class.create(
|
103
|
+
name=func_decl.name,
|
104
|
+
positional_arg_declarations=func_decl.positional_arg_declarations,
|
105
|
+
body=function.body,
|
106
|
+
scope=Scope(parent=self._builder.current_scope),
|
107
|
+
is_lambda=True,
|
108
|
+
**extra_args,
|
109
|
+
),
|
110
|
+
defining_function=self._builder.current_function,
|
111
|
+
)
|
41
112
|
|
42
113
|
@singledispatchmethod
|
43
114
|
def emit(self, statement: QuantumStatement) -> None: # type:ignore[override]
|
44
115
|
raise NotImplementedError(f"Cannot emit {statement!r}")
|
45
116
|
|
46
117
|
@emit.register
|
118
|
+
def _emit_quantum_function_call(self, call: QuantumFunctionCall) -> None:
|
119
|
+
self.emit_quantum_function_call(call)
|
120
|
+
|
47
121
|
def emit_quantum_function_call(self, call: QuantumFunctionCall) -> None:
|
48
122
|
QuantumFunctionCallEmitter(self).emit(call)
|
49
123
|
|
124
|
+
@emit.register
|
125
|
+
def emit_allocate(self, allocate: Allocate) -> None:
|
126
|
+
ShallowEmitter(self, "allocate", components=["size", "target"]).emit(allocate)
|
127
|
+
|
50
128
|
@emit.register
|
51
129
|
def emit_bind(self, bind: BindOperation) -> None:
|
52
130
|
BindEmitter(self).emit(bind)
|
@@ -106,3 +184,66 @@ class GenerativeInterpreter(BaseInterpreter):
|
|
106
184
|
@emit.register
|
107
185
|
def emit_phase(self, phase: PhaseOperation) -> None:
|
108
186
|
ShallowEmitter(self, "phase", components=["expression", "theta"]).emit(phase)
|
187
|
+
|
188
|
+
def _expand_body(self, operation: Closure) -> None:
|
189
|
+
if isinstance(operation, FunctionClosure) and operation.name == "permute":
|
190
|
+
# special expansion since permute is generative
|
191
|
+
self._expand_permute()
|
192
|
+
elif isinstance(operation, GenerativeClosure):
|
193
|
+
args = [
|
194
|
+
self.evaluate(param.name)
|
195
|
+
for param in operation.positional_arg_declarations
|
196
|
+
]
|
197
|
+
emit_generative_statements(self, operation, args)
|
198
|
+
else:
|
199
|
+
super()._expand_body(operation)
|
200
|
+
|
201
|
+
def _expand_permute(self) -> None:
|
202
|
+
functions = self.evaluate("functions").as_type(list)
|
203
|
+
functions_permutation = permutation(np.array(range(len(functions))))
|
204
|
+
calls: list[QuantumFunctionCall] = []
|
205
|
+
for function_index in functions_permutation:
|
206
|
+
permute_call = QuantumFunctionCall(
|
207
|
+
function=OperandIdentifier(
|
208
|
+
name="functions", index=Expression(expr=f"{function_index}")
|
209
|
+
)
|
210
|
+
)
|
211
|
+
permute_call.set_func_decl(permute.func_decl)
|
212
|
+
calls.append(permute_call)
|
213
|
+
self._expand_block(calls, "body")
|
214
|
+
|
215
|
+
def update_generative_functions(
|
216
|
+
self, generative_functions: dict[str, GenerativeQFunc]
|
217
|
+
) -> None:
|
218
|
+
add_generative_functions_to_scope(
|
219
|
+
list(generative_functions.values()), self._top_level_scope
|
220
|
+
)
|
221
|
+
for name, gen_func in generative_functions.items():
|
222
|
+
if gen_func.compilation_metadata is not None:
|
223
|
+
self._functions_compilation_metadata[name] = (
|
224
|
+
gen_func.compilation_metadata
|
225
|
+
)
|
226
|
+
|
227
|
+
def update_declarative_functions(
|
228
|
+
self,
|
229
|
+
functions: dict[str, NativeFunctionDefinition],
|
230
|
+
qmodule: ModelStateContainer,
|
231
|
+
) -> None:
|
232
|
+
add_functions_to_scope(list(functions.values()), self._top_level_scope)
|
233
|
+
for dec_func_name in functions:
|
234
|
+
if dec_func_name in qmodule.functions_compilation_metadata:
|
235
|
+
self._functions_compilation_metadata[dec_func_name] = (
|
236
|
+
qmodule.functions_compilation_metadata[dec_func_name]
|
237
|
+
)
|
238
|
+
|
239
|
+
def add_purely_declarative_function(self, function: FunctionClosure) -> None:
|
240
|
+
functions_to_add = [function.name] + QMODULE.function_dependencies[
|
241
|
+
function.name
|
242
|
+
]
|
243
|
+
for func in functions_to_add:
|
244
|
+
if func not in self._expanded_functions and func in QMODULE.native_defs:
|
245
|
+
self._expanded_functions[func] = QMODULE.native_defs[func]
|
246
|
+
if func in QMODULE.functions_compilation_metadata:
|
247
|
+
self._expanded_functions_compilation_metadata[func] = (
|
248
|
+
QMODULE.functions_compilation_metadata[func]
|
249
|
+
)
|
@@ -8,9 +8,6 @@ from typing import (
|
|
8
8
|
)
|
9
9
|
|
10
10
|
from classiq.interface.debug_info.debug_info import FunctionDebugInfo
|
11
|
-
from classiq.interface.generator.functions.port_declaration import (
|
12
|
-
PortDeclarationDirection,
|
13
|
-
)
|
14
11
|
from classiq.interface.generator.generated_circuit_data import OperationLevel
|
15
12
|
from classiq.interface.model.classical_parameter_declaration import (
|
16
13
|
ClassicalParameterDeclaration,
|
@@ -23,10 +20,6 @@ from classiq.interface.model.quantum_function_declaration import (
|
|
23
20
|
NamedParamsQuantumFunctionDeclaration,
|
24
21
|
PositionalArg,
|
25
22
|
)
|
26
|
-
from classiq.interface.model.quantum_lambda_function import (
|
27
|
-
OperandIdentifier,
|
28
|
-
QuantumLambdaFunction,
|
29
|
-
)
|
30
23
|
from classiq.interface.model.quantum_statement import QuantumStatement
|
31
24
|
from classiq.interface.model.variable_declaration_statement import (
|
32
25
|
VariableDeclarationStatement,
|
@@ -35,7 +28,7 @@ from classiq.interface.model.variable_declaration_statement import (
|
|
35
28
|
from classiq.model_expansions.capturing.captured_vars import (
|
36
29
|
validate_args_are_not_propagated,
|
37
30
|
)
|
38
|
-
from classiq.model_expansions.closure import FunctionClosure
|
31
|
+
from classiq.model_expansions.closure import FunctionClosure
|
39
32
|
from classiq.model_expansions.evaluators.argument_types import (
|
40
33
|
add_information_from_output_arguments,
|
41
34
|
)
|
@@ -52,7 +45,6 @@ from classiq.model_expansions.quantum_operations.emitter import (
|
|
52
45
|
from classiq.model_expansions.scope import Evaluated, QuantumSymbol, Scope
|
53
46
|
from classiq.model_expansions.transformers.var_splitter import VarSplitter
|
54
47
|
from classiq.qmod.builtins.functions import allocate, free
|
55
|
-
from classiq.qmod.model_state_container import QMODULE
|
56
48
|
|
57
49
|
if TYPE_CHECKING:
|
58
50
|
from classiq.model_expansions.interpreters.base_interpreter import BaseInterpreter
|
@@ -105,45 +97,16 @@ class CallEmitter(Generic[QuantumStatementT], Emitter[QuantumStatementT], VarSpl
|
|
105
97
|
function, evaluated_args
|
106
98
|
)
|
107
99
|
new_positional_arg_decls = new_declaration.positional_arg_declarations
|
108
|
-
|
109
|
-
if (
|
110
|
-
self._interpreter.is_shallow
|
111
|
-
and self._is_function_purely_declarative(function)
|
112
|
-
and self._are_args_purely_declarative(args)
|
113
|
-
):
|
100
|
+
if not self.should_expand_function(function, evaluated_args):
|
114
101
|
is_atomic = True
|
115
|
-
self.
|
116
|
-
|
117
|
-
if not is_atomic: # perform monomorphization per interpreted parameters set
|
118
|
-
self._add_params_to_scope(
|
119
|
-
new_positional_arg_decls, evaluated_args, function
|
102
|
+
new_declaration = self._expanded_functions_by_name.get(
|
103
|
+
function.name, new_declaration
|
120
104
|
)
|
121
|
-
|
122
|
-
|
105
|
+
else:
|
106
|
+
is_atomic = False
|
107
|
+
new_declaration = self._expand_function(
|
108
|
+
evaluated_args, new_declaration, function
|
123
109
|
)
|
124
|
-
function_context = cast(FunctionContext, context)
|
125
|
-
closure_id = function_context.closure.closure_id
|
126
|
-
function_def = self._expanded_functions.get(closure_id)
|
127
|
-
if function_def is None:
|
128
|
-
function_def = self._create_function_definition(function_context)
|
129
|
-
self._expanded_functions[closure_id] = function_def
|
130
|
-
self._top_level_scope[function_def.name] = Evaluated(
|
131
|
-
value=function_context.closure.with_new_declaration(function_def)
|
132
|
-
)
|
133
|
-
compilation_metadata = self._functions_compilation_metadata.get(
|
134
|
-
function.name
|
135
|
-
)
|
136
|
-
if compilation_metadata is not None:
|
137
|
-
self._expanded_functions_compilation_metadata[function_def.name] = (
|
138
|
-
compilation_metadata
|
139
|
-
)
|
140
|
-
else:
|
141
|
-
self._expanded_functions_compilation_metadata[
|
142
|
-
function_def.name
|
143
|
-
].occurrences_number += 1
|
144
|
-
|
145
|
-
new_declaration = function_def
|
146
|
-
new_function_name = function_def.name
|
147
110
|
|
148
111
|
new_positional_args = self._get_new_positional_args(
|
149
112
|
evaluated_args, is_atomic, new_positional_arg_decls
|
@@ -154,8 +117,7 @@ class CallEmitter(Generic[QuantumStatementT], Emitter[QuantumStatementT], VarSpl
|
|
154
117
|
validate_args_are_not_propagated(new_positional_args, captured_args)
|
155
118
|
new_positional_args.extend(captured_args)
|
156
119
|
new_call = QuantumFunctionCall(
|
157
|
-
function=
|
158
|
-
positional_args=new_positional_args,
|
120
|
+
function=new_declaration.name, positional_args=new_positional_args
|
159
121
|
)
|
160
122
|
is_allocate_or_free = (
|
161
123
|
new_call.func_name == allocate.func_decl.name
|
@@ -186,6 +148,40 @@ class CallEmitter(Generic[QuantumStatementT], Emitter[QuantumStatementT], VarSpl
|
|
186
148
|
new_call.set_func_decl(new_declaration)
|
187
149
|
return new_call
|
188
150
|
|
151
|
+
def should_expand_function(
|
152
|
+
self, function: FunctionClosure, args: list[Evaluated]
|
153
|
+
) -> bool:
|
154
|
+
return not function.is_atomic
|
155
|
+
|
156
|
+
def _expand_function(
|
157
|
+
self,
|
158
|
+
args: list[Evaluated],
|
159
|
+
decl: NamedParamsQuantumFunctionDeclaration,
|
160
|
+
function: FunctionClosure,
|
161
|
+
) -> NamedParamsQuantumFunctionDeclaration:
|
162
|
+
self._add_params_to_scope(decl.positional_arg_declarations, args, function)
|
163
|
+
context = self._expand_operation(function.with_new_declaration(decl))
|
164
|
+
function_context = cast(FunctionContext, context)
|
165
|
+
closure_id = function_context.closure.closure_id
|
166
|
+
if closure_id in self._expanded_functions:
|
167
|
+
function_def = self._expanded_functions[closure_id]
|
168
|
+
self._expanded_functions_compilation_metadata[
|
169
|
+
function_def.name
|
170
|
+
].occurrences_number += 1
|
171
|
+
return function_def
|
172
|
+
|
173
|
+
function_def = self._create_function_definition(function_context)
|
174
|
+
self._expanded_functions[closure_id] = function_def
|
175
|
+
self._top_level_scope[function_def.name] = Evaluated(
|
176
|
+
value=function_context.closure.with_new_declaration(function_def)
|
177
|
+
)
|
178
|
+
compilation_metadata = self._functions_compilation_metadata.get(function.name)
|
179
|
+
if compilation_metadata is not None:
|
180
|
+
self._expanded_functions_compilation_metadata[function_def.name] = (
|
181
|
+
compilation_metadata
|
182
|
+
)
|
183
|
+
return function_def
|
184
|
+
|
189
185
|
def _create_function_definition(
|
190
186
|
self, function_context: FunctionContext
|
191
187
|
) -> NativeFunctionDefinition:
|
@@ -268,47 +264,3 @@ class CallEmitter(Generic[QuantumStatementT], Emitter[QuantumStatementT], VarSpl
|
|
268
264
|
evaluated_args,
|
269
265
|
),
|
270
266
|
)
|
271
|
-
|
272
|
-
def _is_function_purely_declarative(self, function: FunctionClosure) -> bool:
|
273
|
-
if function.name not in QMODULE.native_defs:
|
274
|
-
return False
|
275
|
-
|
276
|
-
if isinstance(function, GenerativeClosure):
|
277
|
-
return False
|
278
|
-
|
279
|
-
if any(
|
280
|
-
not param.quantum_type.is_instantiated
|
281
|
-
for param in function.positional_arg_declarations
|
282
|
-
if isinstance(param, PortDeclaration)
|
283
|
-
and param.direction == PortDeclarationDirection.Output
|
284
|
-
):
|
285
|
-
return False
|
286
|
-
|
287
|
-
dependencies = QMODULE.function_dependencies[function.name]
|
288
|
-
return self._are_identifiers_purely_declarative(dependencies)
|
289
|
-
|
290
|
-
def _are_args_purely_declarative(self, args: list[ArgValue]) -> bool:
|
291
|
-
if any(
|
292
|
-
isinstance(arg, (OperandIdentifier, QuantumLambdaFunction))
|
293
|
-
or (
|
294
|
-
isinstance(arg, list)
|
295
|
-
and any(
|
296
|
-
isinstance(item, (OperandIdentifier, QuantumLambdaFunction))
|
297
|
-
for item in arg
|
298
|
-
)
|
299
|
-
)
|
300
|
-
for arg in args
|
301
|
-
):
|
302
|
-
return False
|
303
|
-
|
304
|
-
dependencies = [arg for arg in args if isinstance(arg, str)]
|
305
|
-
dependencies += [
|
306
|
-
cast(str, item) for arg in args if isinstance(arg, list) for item in arg
|
307
|
-
]
|
308
|
-
return self._are_identifiers_purely_declarative(dependencies)
|
309
|
-
|
310
|
-
def _are_identifiers_purely_declarative(self, dependencies: list[str]) -> bool:
|
311
|
-
return not any(
|
312
|
-
isinstance(self._current_scope[dep].value, GenerativeClosure)
|
313
|
-
for dep in dependencies
|
314
|
-
)
|