classiq 0.63.1__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/analyzer/url_utils.py +2 -3
- 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/analyzer/result.py +1 -2
- classiq/interface/backend/backend_preferences.py +1 -9
- classiq/interface/executor/result.py +6 -3
- classiq/interface/generator/expressions/qmod_qarray_proxy.py +11 -13
- classiq/interface/generator/functions/type_name.py +6 -0
- classiq/interface/helpers/datastructures.py +26 -0
- classiq/interface/interface_version.py +1 -1
- classiq/interface/model/allocate.py +16 -0
- classiq/interface/model/handle_binding.py +11 -3
- classiq/interface/model/quantum_type.py +26 -0
- classiq/interface/model/statement_block.py +2 -0
- classiq/interface/server/routes.py +5 -0
- classiq/model_expansions/atomic_expression_functions_defs.py +6 -6
- classiq/model_expansions/capturing/captured_vars.py +27 -10
- classiq/model_expansions/evaluators/arg_type_match.py +4 -7
- classiq/model_expansions/evaluators/quantum_type_utils.py +25 -8
- classiq/model_expansions/expression_evaluator.py +8 -2
- classiq/model_expansions/function_builder.py +35 -11
- classiq/model_expansions/generative_functions.py +6 -4
- classiq/model_expansions/interpreters/__init__.py +0 -0
- classiq/model_expansions/interpreters/base_interpreter.py +263 -0
- classiq/model_expansions/interpreters/frontend_generative_interpreter.py +28 -0
- classiq/model_expansions/interpreters/generative_interpreter.py +249 -0
- classiq/model_expansions/model_tables.py +1 -92
- classiq/model_expansions/quantum_operations/__init__.py +0 -10
- classiq/model_expansions/quantum_operations/call_emitter.py +45 -93
- classiq/model_expansions/quantum_operations/declarative_call_emitter.py +87 -0
- classiq/model_expansions/quantum_operations/emitter.py +7 -2
- classiq/model_expansions/quantum_operations/quantum_function_call.py +11 -2
- classiq/model_expansions/quantum_operations/shallow_emitter.py +22 -3
- classiq/model_expansions/scope.py +15 -15
- classiq/model_expansions/scope_initialization.py +11 -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/declaration_inferrer.py +0 -3
- classiq/qmod/generative.py +4 -4
- classiq/qmod/native/pretty_printer.py +9 -1
- classiq/qmod/pretty_print/pretty_printer.py +12 -1
- classiq/qmod/qfunc.py +4 -2
- classiq/qmod/qmod_variable.py +55 -48
- classiq/qmod/quantum_function.py +7 -5
- 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 +23 -1
- {classiq-0.63.1.dist-info → classiq-0.65.1.dist-info}/METADATA +1 -1
- {classiq-0.63.1.dist-info → classiq-0.65.1.dist-info}/RECORD +66 -67
- classiq/interface/helpers/dotdict.py +0 -18
- classiq/model_expansions/interpreter.py +0 -475
- classiq/model_expansions/quantum_operations/control.py +0 -290
- classiq/model_expansions/quantum_operations/expression_operation.py +0 -103
- classiq/model_expansions/quantum_operations/inplace_binary_operation.py +0 -535
- classiq/model_expansions/quantum_operations/invert.py +0 -36
- classiq/model_expansions/quantum_operations/phase.py +0 -187
- classiq/model_expansions/quantum_operations/power.py +0 -71
- classiq/model_expansions/quantum_operations/quantum_assignment_operation.py +0 -230
- classiq/model_expansions/quantum_operations/within_apply.py +0 -25
- classiq/qmod/semantics/annotation.py +0 -36
- /classiq/qmod/semantics/{qstruct_annotator.py → annotation/qstruct_annotator.py} +0 -0
- {classiq-0.63.1.dist-info → classiq-0.65.1.dist-info}/WHEEL +0 -0
@@ -0,0 +1,249 @@
|
|
1
|
+
from functools import singledispatchmethod
|
2
|
+
from typing import Any
|
3
|
+
|
4
|
+
import numpy as np
|
5
|
+
from numpy.random import permutation
|
6
|
+
|
7
|
+
from classiq.interface.generator.expressions.expression import Expression
|
8
|
+
from classiq.interface.generator.functions.builtins.internal_operators import (
|
9
|
+
CONTROL_OPERATOR_NAME,
|
10
|
+
INVERT_OPERATOR_NAME,
|
11
|
+
WITHIN_APPLY_NAME,
|
12
|
+
)
|
13
|
+
from classiq.interface.model.allocate import Allocate
|
14
|
+
from classiq.interface.model.bind_operation import BindOperation
|
15
|
+
from classiq.interface.model.classical_if import ClassicalIf
|
16
|
+
from classiq.interface.model.control import Control
|
17
|
+
from classiq.interface.model.inplace_binary_operation import InplaceBinaryOperation
|
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
|
21
|
+
from classiq.interface.model.phase_operation import PhaseOperation
|
22
|
+
from classiq.interface.model.power import Power
|
23
|
+
from classiq.interface.model.quantum_expressions.quantum_expression import (
|
24
|
+
QuantumAssignmentOperation,
|
25
|
+
)
|
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
|
+
)
|
34
|
+
from classiq.interface.model.quantum_statement import QuantumStatement
|
35
|
+
from classiq.interface.model.repeat import Repeat
|
36
|
+
from classiq.interface.model.variable_declaration_statement import (
|
37
|
+
VariableDeclarationStatement,
|
38
|
+
)
|
39
|
+
from classiq.interface.model.within_apply_operation import WithinApply
|
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
|
48
|
+
from classiq.model_expansions.interpreters.base_interpreter import BaseInterpreter
|
49
|
+
from classiq.model_expansions.quantum_operations import (
|
50
|
+
BindEmitter,
|
51
|
+
ClassicalIfEmitter,
|
52
|
+
QuantumFunctionCallEmitter,
|
53
|
+
RepeatEmitter,
|
54
|
+
VariableDeclarationStatementEmitter,
|
55
|
+
)
|
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
|
65
|
+
|
66
|
+
|
67
|
+
class GenerativeInterpreter(BaseInterpreter):
|
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
|
+
)
|
112
|
+
|
113
|
+
@singledispatchmethod
|
114
|
+
def emit(self, statement: QuantumStatement) -> None: # type:ignore[override]
|
115
|
+
raise NotImplementedError(f"Cannot emit {statement!r}")
|
116
|
+
|
117
|
+
@emit.register
|
118
|
+
def _emit_quantum_function_call(self, call: QuantumFunctionCall) -> None:
|
119
|
+
self.emit_quantum_function_call(call)
|
120
|
+
|
121
|
+
def emit_quantum_function_call(self, call: QuantumFunctionCall) -> None:
|
122
|
+
QuantumFunctionCallEmitter(self).emit(call)
|
123
|
+
|
124
|
+
@emit.register
|
125
|
+
def emit_allocate(self, allocate: Allocate) -> None:
|
126
|
+
ShallowEmitter(self, "allocate", components=["size", "target"]).emit(allocate)
|
127
|
+
|
128
|
+
@emit.register
|
129
|
+
def emit_bind(self, bind: BindOperation) -> None:
|
130
|
+
BindEmitter(self).emit(bind)
|
131
|
+
|
132
|
+
@emit.register
|
133
|
+
def emit_quantum_assignment_operation(self, op: QuantumAssignmentOperation) -> None:
|
134
|
+
ShallowEmitter(
|
135
|
+
self, "assignment_operation", components=["expression", "result_var"]
|
136
|
+
).emit(op)
|
137
|
+
|
138
|
+
@emit.register
|
139
|
+
def emit_inplace_binary_operation(self, op: InplaceBinaryOperation) -> None:
|
140
|
+
ShallowEmitter(
|
141
|
+
self, "inplace_binary_operation", components=["target", "value"]
|
142
|
+
).emit(op)
|
143
|
+
|
144
|
+
@emit.register
|
145
|
+
def emit_variable_declaration(
|
146
|
+
self, variable_declaration: VariableDeclarationStatement
|
147
|
+
) -> None:
|
148
|
+
VariableDeclarationStatementEmitter(self).emit(variable_declaration)
|
149
|
+
|
150
|
+
@emit.register
|
151
|
+
def emit_classical_if(self, classical_if: ClassicalIf) -> None:
|
152
|
+
ClassicalIfEmitter(self).emit(classical_if)
|
153
|
+
|
154
|
+
@emit.register
|
155
|
+
def emit_within_apply(self, within_apply: WithinApply) -> None:
|
156
|
+
ShallowEmitter(
|
157
|
+
self,
|
158
|
+
WITHIN_APPLY_NAME,
|
159
|
+
components=["within", "apply", "compute", "action"],
|
160
|
+
).emit(within_apply)
|
161
|
+
|
162
|
+
@emit.register
|
163
|
+
def emit_invert(self, invert: Invert) -> None:
|
164
|
+
ShallowEmitter(self, INVERT_OPERATOR_NAME, components=["body"]).emit(invert)
|
165
|
+
|
166
|
+
@emit.register
|
167
|
+
def emit_repeat(self, repeat: Repeat) -> None:
|
168
|
+
RepeatEmitter(self).emit(repeat)
|
169
|
+
|
170
|
+
@emit.register
|
171
|
+
def emit_control(self, control: Control) -> None:
|
172
|
+
ShallowEmitter(
|
173
|
+
self,
|
174
|
+
CONTROL_OPERATOR_NAME,
|
175
|
+
components=["expression", "body", "else_block"],
|
176
|
+
).emit(control)
|
177
|
+
|
178
|
+
@emit.register
|
179
|
+
def emit_power(self, power: Power) -> None:
|
180
|
+
ShallowEmitter(self, CONTROL_OPERATOR_NAME, components=["power", "body"]).emit(
|
181
|
+
power
|
182
|
+
)
|
183
|
+
|
184
|
+
@emit.register
|
185
|
+
def emit_phase(self, phase: PhaseOperation) -> None:
|
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
|
+
)
|
@@ -1,98 +1,7 @@
|
|
1
|
-
from
|
2
|
-
from enum import IntEnum
|
3
|
-
from typing import ClassVar, Generic, Optional, TypeVar
|
1
|
+
from typing import Optional
|
4
2
|
|
5
3
|
from classiq.interface.generator.expressions.handle_identifier import HandleIdentifier
|
6
4
|
from classiq.interface.generator.functions.classical_type import QmodPyObject
|
7
|
-
from classiq.interface.generator.types.enum_declaration import EnumDeclaration
|
8
|
-
from classiq.interface.generator.types.qstruct_declaration import QStructDeclaration
|
9
|
-
from classiq.interface.generator.types.struct_declaration import StructDeclaration
|
10
|
-
|
11
|
-
from classiq.qmod.builtins.enums import BUILTIN_ENUM_DECLARATIONS
|
12
|
-
from classiq.qmod.builtins.structs import BUILTIN_STRUCT_DECLARATIONS
|
13
|
-
from classiq.qmod.model_state_container import QMODULE
|
14
|
-
|
15
|
-
DeclarationType = TypeVar(
|
16
|
-
"DeclarationType", EnumDeclaration, StructDeclaration, QStructDeclaration
|
17
|
-
)
|
18
|
-
|
19
|
-
|
20
|
-
class TypeTable(Generic[DeclarationType], ABC):
|
21
|
-
def __init__(self, user_types: list[DeclarationType]) -> None:
|
22
|
-
self._all_types: dict[str, DeclarationType] = self.builtins.copy()
|
23
|
-
for t in user_types:
|
24
|
-
assert t.name not in self._all_types # FIXME: issue user error (CAD-7856)
|
25
|
-
self._all_types[t.name] = t
|
26
|
-
|
27
|
-
@property
|
28
|
-
@abstractmethod
|
29
|
-
def builtins(self) -> dict[str, DeclarationType]:
|
30
|
-
pass
|
31
|
-
|
32
|
-
def __getitem__(self, key: str) -> DeclarationType:
|
33
|
-
return self._all_types[key]
|
34
|
-
|
35
|
-
def __setitem__(self, key: str, value: DeclarationType) -> None:
|
36
|
-
self._all_types[key] = value
|
37
|
-
|
38
|
-
def __contains__(self, key: str) -> bool:
|
39
|
-
return key in self._all_types
|
40
|
-
|
41
|
-
def all_types(self) -> dict[str, DeclarationType]:
|
42
|
-
return self._all_types
|
43
|
-
|
44
|
-
|
45
|
-
class EnumTable(TypeTable[EnumDeclaration]):
|
46
|
-
def __init__(self, user_types: list[EnumDeclaration]) -> None:
|
47
|
-
super().__init__(user_types)
|
48
|
-
|
49
|
-
@property
|
50
|
-
def builtins(self) -> dict[str, EnumDeclaration]:
|
51
|
-
return BUILTIN_ENUM_DECLARATIONS
|
52
|
-
|
53
|
-
@property
|
54
|
-
def enums(self) -> dict[str, IntEnum]:
|
55
|
-
return {
|
56
|
-
enum_decl.name: enum_decl.create_enum()
|
57
|
-
for enum_decl in self.all_types().values()
|
58
|
-
}
|
59
|
-
|
60
|
-
|
61
|
-
class StructTable(TypeTable[StructDeclaration]):
|
62
|
-
@property
|
63
|
-
def builtins(self) -> dict[str, StructDeclaration]:
|
64
|
-
return BUILTIN_STRUCT_DECLARATIONS
|
65
|
-
|
66
|
-
|
67
|
-
class QStructTable(TypeTable[QStructDeclaration]):
|
68
|
-
@property
|
69
|
-
def builtins(self) -> dict[str, QStructDeclaration]:
|
70
|
-
return {}
|
71
|
-
|
72
|
-
|
73
|
-
class SymbolTable:
|
74
|
-
enum_table: ClassVar[EnumTable] = EnumTable([])
|
75
|
-
type_table: ClassVar[StructTable] = StructTable([])
|
76
|
-
qstruct_table: ClassVar[QStructTable] = QStructTable([])
|
77
|
-
|
78
|
-
@classmethod
|
79
|
-
def init_user_enums(cls, user_enums: list[EnumDeclaration]) -> None:
|
80
|
-
cls.enum_table = EnumTable(user_enums)
|
81
|
-
QMODULE.enum_decls = {enum_decl.name: enum_decl for enum_decl in user_enums}
|
82
|
-
|
83
|
-
@classmethod
|
84
|
-
def init_user_types(cls, user_types: list[StructDeclaration]) -> None:
|
85
|
-
cls.type_table = StructTable(user_types)
|
86
|
-
QMODULE.type_decls = {
|
87
|
-
struct_decl.name: struct_decl for struct_decl in user_types
|
88
|
-
}
|
89
|
-
|
90
|
-
@classmethod
|
91
|
-
def init_user_qstructs(cls, user_qstructs: list[QStructDeclaration]) -> None:
|
92
|
-
cls.qstruct_table = QStructTable(user_qstructs)
|
93
|
-
QMODULE.qstruct_decls = {
|
94
|
-
qstruct_decl.name: qstruct_decl for qstruct_decl in user_qstructs
|
95
|
-
}
|
96
5
|
|
97
6
|
|
98
7
|
class HandleTable:
|
@@ -1,14 +1,5 @@
|
|
1
1
|
from classiq.model_expansions.quantum_operations.bind import BindEmitter
|
2
2
|
from classiq.model_expansions.quantum_operations.classicalif import ClassicalIfEmitter
|
3
|
-
from classiq.model_expansions.quantum_operations.control import ControlEmitter
|
4
|
-
from classiq.model_expansions.quantum_operations.inplace_binary_operation import (
|
5
|
-
InplaceBinaryOperationEmitter,
|
6
|
-
)
|
7
|
-
from classiq.model_expansions.quantum_operations.invert import InvertEmitter
|
8
|
-
from classiq.model_expansions.quantum_operations.power import PowerEmitter
|
9
|
-
from classiq.model_expansions.quantum_operations.quantum_assignment_operation import (
|
10
|
-
QuantumAssignmentOperationEmitter,
|
11
|
-
)
|
12
3
|
from classiq.model_expansions.quantum_operations.quantum_function_call import (
|
13
4
|
QuantumFunctionCallEmitter,
|
14
5
|
)
|
@@ -16,4 +7,3 @@ from classiq.model_expansions.quantum_operations.repeat import RepeatEmitter
|
|
16
7
|
from classiq.model_expansions.quantum_operations.variable_decleration import (
|
17
8
|
VariableDeclarationStatementEmitter,
|
18
9
|
)
|
19
|
-
from classiq.model_expansions.quantum_operations.within_apply import WithinApplyEmitter
|
@@ -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,14 +45,13 @@ 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
|
-
from classiq.model_expansions.
|
50
|
+
from classiq.model_expansions.interpreters.base_interpreter import BaseInterpreter
|
59
51
|
|
60
52
|
|
61
53
|
class CallEmitter(Generic[QuantumStatementT], Emitter[QuantumStatementT], VarSplitter):
|
62
|
-
def __init__(self, interpreter: "
|
54
|
+
def __init__(self, interpreter: "BaseInterpreter") -> None:
|
63
55
|
Emitter.__init__(self, interpreter)
|
64
56
|
VarSplitter.__init__(self, interpreter._builder.current_scope)
|
65
57
|
|
@@ -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
|
-
)
|
@@ -0,0 +1,87 @@
|
|
1
|
+
from itertools import chain
|
2
|
+
from typing import TYPE_CHECKING, Generic
|
3
|
+
|
4
|
+
from classiq.interface.generator.functions.port_declaration import (
|
5
|
+
PortDeclarationDirection,
|
6
|
+
)
|
7
|
+
from classiq.interface.model.port_declaration import PortDeclaration
|
8
|
+
|
9
|
+
from classiq.model_expansions.closure import FunctionClosure, GenerativeClosure
|
10
|
+
from classiq.model_expansions.quantum_operations.call_emitter import CallEmitter
|
11
|
+
from classiq.model_expansions.quantum_operations.emitter import QuantumStatementT
|
12
|
+
from classiq.model_expansions.scope import Evaluated
|
13
|
+
from classiq.qmod.model_state_container import QMODULE
|
14
|
+
|
15
|
+
if TYPE_CHECKING:
|
16
|
+
from classiq.model_expansions.interpreters.generative_interpreter import (
|
17
|
+
GenerativeInterpreter,
|
18
|
+
)
|
19
|
+
|
20
|
+
|
21
|
+
class DeclarativeCallEmitter(
|
22
|
+
Generic[QuantumStatementT], CallEmitter[QuantumStatementT]
|
23
|
+
):
|
24
|
+
_interpreter: "GenerativeInterpreter"
|
25
|
+
|
26
|
+
def __init__(self, interpreter: "GenerativeInterpreter") -> None:
|
27
|
+
super().__init__(interpreter)
|
28
|
+
|
29
|
+
def should_expand_function(
|
30
|
+
self, function: FunctionClosure, args: list[Evaluated]
|
31
|
+
) -> bool:
|
32
|
+
if not super().should_expand_function(function, args):
|
33
|
+
return False
|
34
|
+
|
35
|
+
if self._is_function_purely_declarative(
|
36
|
+
function
|
37
|
+
) and self._are_args_purely_declarative(args):
|
38
|
+
self._interpreter.add_purely_declarative_function(function)
|
39
|
+
return False
|
40
|
+
|
41
|
+
return True
|
42
|
+
|
43
|
+
def _is_function_purely_declarative(self, function: FunctionClosure) -> bool:
|
44
|
+
if function.name not in QMODULE.native_defs:
|
45
|
+
return False
|
46
|
+
|
47
|
+
if isinstance(function, GenerativeClosure):
|
48
|
+
return False
|
49
|
+
|
50
|
+
if any(
|
51
|
+
not param.quantum_type.is_instantiated
|
52
|
+
for param in function.positional_arg_declarations
|
53
|
+
if isinstance(param, PortDeclaration)
|
54
|
+
and param.direction == PortDeclarationDirection.Output
|
55
|
+
):
|
56
|
+
return False
|
57
|
+
|
58
|
+
dependencies = QMODULE.function_dependencies[function.name]
|
59
|
+
return self._are_identifiers_purely_declarative(dependencies)
|
60
|
+
|
61
|
+
def _are_args_purely_declarative(self, args: list[Evaluated]) -> bool:
|
62
|
+
values = [arg.value for arg in args]
|
63
|
+
function_inputs: list[FunctionClosure] = list(
|
64
|
+
chain.from_iterable(
|
65
|
+
(
|
66
|
+
[arg]
|
67
|
+
if isinstance(arg, FunctionClosure)
|
68
|
+
else (
|
69
|
+
arg
|
70
|
+
if isinstance(arg, list)
|
71
|
+
and any(isinstance(item, FunctionClosure) for item in arg)
|
72
|
+
else []
|
73
|
+
)
|
74
|
+
)
|
75
|
+
for arg in values
|
76
|
+
)
|
77
|
+
)
|
78
|
+
if any(func.is_lambda for func in function_inputs):
|
79
|
+
return False
|
80
|
+
dependencies = [func.name for func in function_inputs if not func.is_lambda]
|
81
|
+
return self._are_identifiers_purely_declarative(dependencies)
|
82
|
+
|
83
|
+
def _are_identifiers_purely_declarative(self, dependencies: list[str]) -> bool:
|
84
|
+
return not any(
|
85
|
+
isinstance(self._current_scope[dep].value, GenerativeClosure)
|
86
|
+
for dep in dependencies
|
87
|
+
)
|
@@ -19,6 +19,7 @@ from classiq.interface.generator.expressions.expression import Expression
|
|
19
19
|
from classiq.interface.generator.functions.port_declaration import (
|
20
20
|
PortDeclarationDirection,
|
21
21
|
)
|
22
|
+
from classiq.interface.helpers.pydantic_model_helpers import nameables_to_dict
|
22
23
|
from classiq.interface.model.handle_binding import HandleBinding
|
23
24
|
from classiq.interface.model.native_function_definition import NativeFunctionDefinition
|
24
25
|
from classiq.interface.model.quantum_function_declaration import (
|
@@ -40,13 +41,13 @@ from classiq.model_expansions.visitors.variable_references import VarRefCollecto
|
|
40
41
|
from classiq.qmod.quantum_function import GenerativeQFunc
|
41
42
|
|
42
43
|
if TYPE_CHECKING:
|
43
|
-
from classiq.model_expansions.
|
44
|
+
from classiq.model_expansions.interpreters.base_interpreter import BaseInterpreter
|
44
45
|
|
45
46
|
QuantumStatementT = TypeVar("QuantumStatementT", bound=QuantumStatement)
|
46
47
|
|
47
48
|
|
48
49
|
class Emitter(Generic[QuantumStatementT]):
|
49
|
-
def __init__(self, interpreter: "
|
50
|
+
def __init__(self, interpreter: "BaseInterpreter") -> None:
|
50
51
|
self._interpreter = interpreter
|
51
52
|
|
52
53
|
self._machine_precision = self._interpreter._model.preferences.machine_precision
|
@@ -80,6 +81,10 @@ class Emitter(Generic[QuantumStatementT]):
|
|
80
81
|
def _expanded_functions(self) -> dict[str, NativeFunctionDefinition]:
|
81
82
|
return self._interpreter._expanded_functions
|
82
83
|
|
84
|
+
@property
|
85
|
+
def _expanded_functions_by_name(self) -> dict[str, NativeFunctionDefinition]:
|
86
|
+
return nameables_to_dict(list(self._interpreter._expanded_functions.values()))
|
87
|
+
|
83
88
|
@property
|
84
89
|
def _counted_name_allocator(self) -> CountedNameAllocator:
|
85
90
|
return self._interpreter._counted_name_allocator
|