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
@@ -34,6 +34,10 @@ if TYPE_CHECKING:
|
|
34
34
|
from classiq.model_expansions.closure import FunctionClosure
|
35
35
|
|
36
36
|
|
37
|
+
ALREADY_ALLOCATED_MESSAGE = "Cannot allocate variable '{}', it is already initialized"
|
38
|
+
ALREADY_FREED_MESSAGE = "Cannot free variable '{}', it is already uninitialized"
|
39
|
+
|
40
|
+
|
37
41
|
class PortDirection(StrEnum):
|
38
42
|
Input = "input"
|
39
43
|
Inout = "inout"
|
@@ -141,7 +145,14 @@ class CapturedVars:
|
|
141
145
|
isinstance(captured_handle.handle, NestedHandleBinding)
|
142
146
|
and captured_handle.direction != PortDirection.Inout
|
143
147
|
):
|
144
|
-
|
148
|
+
verb = (
|
149
|
+
"free"
|
150
|
+
if captured_handle.direction == PortDirection.Input
|
151
|
+
else "allocate"
|
152
|
+
)
|
153
|
+
raise ClassiqExpansionError(
|
154
|
+
f"Cannot partially {verb} variable {captured_handle.handle.name}"
|
155
|
+
)
|
145
156
|
|
146
157
|
new_captured_handles = []
|
147
158
|
for existing_captured_handle in self._captured_handles:
|
@@ -174,7 +185,9 @@ class CapturedVars:
|
|
174
185
|
return captured_handle.change_direction(PortDirection.Inout)
|
175
186
|
if captured_handle.direction == PortDirection.Outin:
|
176
187
|
return captured_handle.change_direction(PortDirection.Input)
|
177
|
-
raise
|
188
|
+
raise ClassiqExpansionError(
|
189
|
+
ALREADY_FREED_MESSAGE.format(captured_handle.handle)
|
190
|
+
)
|
178
191
|
if existing_captured_handle.direction == PortDirection.Output:
|
179
192
|
if captured_handle.direction == PortDirection.Input:
|
180
193
|
return captured_handle.change_direction(PortDirection.Outin)
|
@@ -182,8 +195,8 @@ class CapturedVars:
|
|
182
195
|
PortDirection.Output,
|
183
196
|
PortDirection.Outin,
|
184
197
|
):
|
185
|
-
raise
|
186
|
-
|
198
|
+
raise ClassiqExpansionError(
|
199
|
+
ALREADY_ALLOCATED_MESSAGE.format(captured_handle.handle)
|
187
200
|
)
|
188
201
|
return captured_handle.change_direction(PortDirection.Output)
|
189
202
|
if existing_captured_handle.direction == PortDirection.Inout:
|
@@ -191,14 +204,16 @@ class CapturedVars:
|
|
191
204
|
PortDirection.Output,
|
192
205
|
PortDirection.Outin,
|
193
206
|
):
|
194
|
-
raise
|
195
|
-
|
207
|
+
raise ClassiqExpansionError(
|
208
|
+
ALREADY_ALLOCATED_MESSAGE.format(captured_handle.handle)
|
196
209
|
)
|
197
210
|
elif captured_handle.direction in (
|
198
211
|
PortDirection.Input,
|
199
212
|
PortDirection.Inout,
|
200
213
|
):
|
201
|
-
raise
|
214
|
+
raise ClassiqExpansionError(
|
215
|
+
ALREADY_FREED_MESSAGE.format(captured_handle.handle)
|
216
|
+
)
|
202
217
|
return captured_handle
|
203
218
|
|
204
219
|
def _intersect_handles(
|
@@ -211,7 +226,9 @@ class CapturedVars:
|
|
211
226
|
PortDirection.Input,
|
212
227
|
PortDirection.Outin,
|
213
228
|
):
|
214
|
-
raise
|
229
|
+
raise ClassiqExpansionError(
|
230
|
+
ALREADY_FREED_MESSAGE.format(captured_handle.handle)
|
231
|
+
)
|
215
232
|
return existing_captured_handle
|
216
233
|
|
217
234
|
if existing_captured_handle.handle in captured_handle.handle:
|
@@ -219,8 +236,8 @@ class CapturedVars:
|
|
219
236
|
PortDirection.Output,
|
220
237
|
PortDirection.Outin,
|
221
238
|
):
|
222
|
-
raise
|
223
|
-
|
239
|
+
raise ClassiqExpansionError(
|
240
|
+
ALREADY_ALLOCATED_MESSAGE.format(captured_handle.handle)
|
224
241
|
)
|
225
242
|
return captured_handle
|
226
243
|
|
@@ -25,8 +25,8 @@ from classiq.interface.model.quantum_function_declaration import (
|
|
25
25
|
|
26
26
|
from classiq.model_expansions.closure import FunctionClosure
|
27
27
|
from classiq.model_expansions.evaluators.type_type_match import check_signature_match
|
28
|
-
from classiq.model_expansions.model_tables import SymbolTable
|
29
28
|
from classiq.model_expansions.scope import Evaluated, QuantumSymbol
|
29
|
+
from classiq.qmod.model_state_container import QMODULE
|
30
30
|
from classiq.qmod.qmod_parameter import CInt, get_qmod_type
|
31
31
|
|
32
32
|
|
@@ -122,11 +122,11 @@ def _check_classical_type_match(
|
|
122
122
|
type_name = _resolve_type_name(classical_type)
|
123
123
|
type_is_struct = (
|
124
124
|
isinstance(classical_type, TypeName)
|
125
|
-
and classical_type.name in
|
125
|
+
and classical_type.name in QMODULE.type_decls
|
126
126
|
)
|
127
127
|
type_is_enum = (
|
128
128
|
isinstance(classical_type, TypeName)
|
129
|
-
and classical_type.name in
|
129
|
+
and classical_type.name in QMODULE.enum_decls
|
130
130
|
)
|
131
131
|
arg_is_qvar = isinstance(argument, QmodSizedProxy)
|
132
132
|
arg_is_builtin = argument.__class__.__module__ == "builtins"
|
@@ -153,9 +153,6 @@ def _resolve_type_name(classical_type: ConcreteClassicalType) -> str:
|
|
153
153
|
type_name = get_qmod_type(classical_type).__name__
|
154
154
|
if not isinstance(classical_type, TypeName):
|
155
155
|
return type_name
|
156
|
-
if
|
157
|
-
type_name not in SymbolTable.type_table
|
158
|
-
and type_name not in SymbolTable.enum_table
|
159
|
-
):
|
156
|
+
if type_name not in QMODULE.type_decls and type_name not in QMODULE.enum_decls:
|
160
157
|
raise ClassiqExpansionError(f"Undefined type {type_name}")
|
161
158
|
return type_name
|
@@ -1,3 +1,4 @@
|
|
1
|
+
from collections.abc import Sequence
|
1
2
|
from typing import Optional
|
2
3
|
|
3
4
|
from classiq.interface.exceptions import (
|
@@ -10,10 +11,14 @@ from classiq.interface.generator.functions.type_name import (
|
|
10
11
|
TypeName,
|
11
12
|
)
|
12
13
|
from classiq.interface.model.bind_operation import BindOperation
|
14
|
+
from classiq.interface.model.inplace_binary_operation import BinaryOperation
|
15
|
+
from classiq.interface.model.port_declaration import PortDeclaration
|
16
|
+
from classiq.interface.model.quantum_function_declaration import PositionalArg
|
13
17
|
from classiq.interface.model.quantum_type import (
|
14
18
|
QuantumBit,
|
15
19
|
QuantumBitvector,
|
16
20
|
QuantumNumeric,
|
21
|
+
QuantumScalar,
|
17
22
|
QuantumType,
|
18
23
|
)
|
19
24
|
|
@@ -209,14 +214,26 @@ def validate_bind_targets(bind: BindOperation, scope: Scope) -> None:
|
|
209
214
|
)
|
210
215
|
|
211
216
|
|
212
|
-
def
|
213
|
-
|
214
|
-
) ->
|
215
|
-
if not isinstance(
|
217
|
+
def get_inplace_op_scalar_as_numeric(
|
218
|
+
var: QuantumSymbol, operation: BinaryOperation, var_kind: str
|
219
|
+
) -> QuantumNumeric:
|
220
|
+
if not isinstance(var.quantum_type, QuantumScalar):
|
216
221
|
raise ClassiqExpansionError(
|
217
|
-
f"Cannot perform
|
222
|
+
f"Cannot perform inplace {operation.name.lower()} with non-scalar {var_kind} {var.handle}"
|
218
223
|
)
|
219
|
-
if
|
220
|
-
|
221
|
-
|
224
|
+
if isinstance(var.quantum_type, QuantumNumeric):
|
225
|
+
return var.quantum_type
|
226
|
+
if isinstance(var.quantum_type, QuantumBit):
|
227
|
+
return QuantumNumeric(
|
228
|
+
size=Expression(expr="1"),
|
229
|
+
is_signed=Expression(expr="False"),
|
230
|
+
fraction_digits=Expression(expr="0"),
|
222
231
|
)
|
232
|
+
raise ClassiqInternalExpansionError(f"Unexpected scalar type {var.quantum_type}")
|
233
|
+
|
234
|
+
|
235
|
+
def is_signature_monomorphic(params: Sequence[PositionalArg]) -> bool:
|
236
|
+
return all(
|
237
|
+
isinstance(param, PortDeclaration) and param.quantum_type.is_evaluated
|
238
|
+
for param in params
|
239
|
+
)
|
@@ -24,12 +24,13 @@ from classiq.model_expansions.atomic_expression_functions_defs import (
|
|
24
24
|
ATOMIC_EXPRESSION_FUNCTIONS,
|
25
25
|
qmod_val_to_python,
|
26
26
|
)
|
27
|
-
from classiq.model_expansions.model_tables import SymbolTable
|
28
27
|
from classiq.model_expansions.sympy_conversion.expression_to_sympy import (
|
29
28
|
translate_to_sympy,
|
30
29
|
)
|
31
30
|
from classiq.model_expansions.sympy_conversion.sympy_to_python import sympy_to_python
|
32
31
|
from classiq.qmod import symbolic
|
32
|
+
from classiq.qmod.builtins.enums import BUILTIN_ENUM_DECLARATIONS
|
33
|
+
from classiq.qmod.model_state_container import QMODULE
|
33
34
|
|
34
35
|
|
35
36
|
def evaluate_constants(constants: list[Constant]) -> dict[str, EvaluatedExpression]:
|
@@ -56,7 +57,12 @@ def evaluate(
|
|
56
57
|
) -> EvaluatedExpression:
|
57
58
|
model_locals: dict[str, ExpressionValue] = {}
|
58
59
|
model_locals.update(ATOMIC_EXPRESSION_FUNCTIONS)
|
59
|
-
model_locals.update(
|
60
|
+
model_locals.update(
|
61
|
+
{
|
62
|
+
enum_decl.name: enum_decl.create_enum()
|
63
|
+
for enum_decl in (QMODULE.enum_decls | BUILTIN_ENUM_DECLARATIONS).values()
|
64
|
+
}
|
65
|
+
)
|
60
66
|
# locals override builtin-functions
|
61
67
|
model_locals.update({name: expr.value for name, expr in locals_dict.items()})
|
62
68
|
uninitialized_locals = uninitialized_locals or set()
|
@@ -29,7 +29,14 @@ from classiq.model_expansions.capturing.captured_vars import (
|
|
29
29
|
CapturedVars,
|
30
30
|
validate_captured_directions,
|
31
31
|
)
|
32
|
-
from classiq.model_expansions.closure import
|
32
|
+
from classiq.model_expansions.closure import (
|
33
|
+
Closure,
|
34
|
+
FunctionClosure,
|
35
|
+
GenerativeFunctionClosure,
|
36
|
+
)
|
37
|
+
from classiq.model_expansions.evaluators.quantum_type_utils import (
|
38
|
+
is_signature_monomorphic,
|
39
|
+
)
|
33
40
|
from classiq.model_expansions.scope import Scope
|
34
41
|
from classiq.model_expansions.utils.counted_name_allocator import CountedNameAllocator
|
35
42
|
|
@@ -200,16 +207,7 @@ class OperationBuilder:
|
|
200
207
|
def create_definition(
|
201
208
|
self, function_context: FunctionContext
|
202
209
|
) -> NativeFunctionDefinition:
|
203
|
-
name = function_context
|
204
|
-
if name != MAIN_FUNCTION_NAME:
|
205
|
-
for _ in self.current_scope:
|
206
|
-
name = self._counted_name_allocator.allocate(
|
207
|
-
f"{name}_{LAMBDA_KEYWORD + '_0_0_' if function_context.is_lambda else ''}{EXPANDED_KEYWORD}"
|
208
|
-
)
|
209
|
-
if name not in self.current_scope:
|
210
|
-
break
|
211
|
-
else:
|
212
|
-
raise ClassiqInternalExpansionError("Could not allocate function name")
|
210
|
+
name = self._get_expanded_function_name(function_context)
|
213
211
|
new_parameters: list[PortDeclaration] = [
|
214
212
|
param
|
215
213
|
for param in function_context.positional_arg_declarations
|
@@ -221,3 +219,29 @@ class OperationBuilder:
|
|
221
219
|
body=function_context.body,
|
222
220
|
positional_arg_declarations=new_parameters,
|
223
221
|
)
|
222
|
+
|
223
|
+
def _get_expanded_function_name(self, function_context: FunctionContext) -> str:
|
224
|
+
name = function_context.name
|
225
|
+
|
226
|
+
if name == MAIN_FUNCTION_NAME:
|
227
|
+
return name
|
228
|
+
|
229
|
+
if name in self.current_scope:
|
230
|
+
orig_func = self.current_scope[name].value
|
231
|
+
if (
|
232
|
+
isinstance(orig_func, FunctionClosure)
|
233
|
+
and not isinstance(orig_func, GenerativeFunctionClosure)
|
234
|
+
and is_signature_monomorphic(orig_func.positional_arg_declarations)
|
235
|
+
):
|
236
|
+
return name
|
237
|
+
|
238
|
+
for _ in self.current_scope:
|
239
|
+
name = self._counted_name_allocator.allocate(
|
240
|
+
f"{name}_{LAMBDA_KEYWORD + '_0_0_' if function_context.is_lambda else ''}{EXPANDED_KEYWORD}"
|
241
|
+
)
|
242
|
+
if name not in self.current_scope:
|
243
|
+
break
|
244
|
+
else:
|
245
|
+
raise ClassiqInternalExpansionError("Could not allocate function name")
|
246
|
+
|
247
|
+
return name
|
@@ -30,11 +30,13 @@ from classiq.qmod.quantum_expandable import (
|
|
30
30
|
QTerminalCallable,
|
31
31
|
)
|
32
32
|
from classiq.qmod.quantum_function import QFunc
|
33
|
-
from classiq.qmod.semantics.
|
33
|
+
from classiq.qmod.semantics.annotation.call_annotation import resolve_function_calls
|
34
34
|
from classiq.qmod.symbolic_expr import SymbolicExpr
|
35
35
|
|
36
36
|
if TYPE_CHECKING:
|
37
|
-
from classiq.model_expansions.
|
37
|
+
from classiq.model_expansions.interpreters.generative_interpreter import (
|
38
|
+
GenerativeInterpreter,
|
39
|
+
)
|
38
40
|
|
39
41
|
|
40
42
|
class LenList(list):
|
@@ -94,7 +96,7 @@ def translate_ast_arg_to_python_qmod(param: PositionalArg, evaluated: Evaluated)
|
|
94
96
|
|
95
97
|
|
96
98
|
class _InterpreterExpandable(QFunc):
|
97
|
-
def __init__(self, interpreter: "
|
99
|
+
def __init__(self, interpreter: "GenerativeInterpreter"):
|
98
100
|
super().__init__(lambda: None)
|
99
101
|
self._interpreter = interpreter
|
100
102
|
|
@@ -137,7 +139,7 @@ class _InterpreterExpandable(QFunc):
|
|
137
139
|
|
138
140
|
|
139
141
|
def emit_generative_statements(
|
140
|
-
interpreter: "
|
142
|
+
interpreter: "GenerativeInterpreter",
|
141
143
|
operation: GenerativeClosure,
|
142
144
|
args: list[Evaluated],
|
143
145
|
) -> None:
|
File without changes
|
@@ -0,0 +1,263 @@
|
|
1
|
+
import ast
|
2
|
+
from abc import abstractmethod
|
3
|
+
from collections import defaultdict
|
4
|
+
from collections.abc import Sequence
|
5
|
+
from contextlib import nullcontext
|
6
|
+
from functools import singledispatchmethod
|
7
|
+
from typing import Any, Optional, cast
|
8
|
+
|
9
|
+
import sympy
|
10
|
+
from pydantic import ValidationError
|
11
|
+
|
12
|
+
from classiq.interface.exceptions import (
|
13
|
+
ClassiqError,
|
14
|
+
ClassiqExpansionError,
|
15
|
+
ClassiqInternalExpansionError,
|
16
|
+
)
|
17
|
+
from classiq.interface.generator.constant import Constant
|
18
|
+
from classiq.interface.generator.expressions.expression import Expression
|
19
|
+
from classiq.interface.generator.types.compilation_metadata import CompilationMetadata
|
20
|
+
from classiq.interface.model.handle_binding import (
|
21
|
+
FieldHandleBinding,
|
22
|
+
HandleBinding,
|
23
|
+
SlicedHandleBinding,
|
24
|
+
SubscriptHandleBinding,
|
25
|
+
)
|
26
|
+
from classiq.interface.model.model import MAIN_FUNCTION_NAME, Model
|
27
|
+
from classiq.interface.model.native_function_definition import NativeFunctionDefinition
|
28
|
+
from classiq.interface.model.quantum_function_declaration import (
|
29
|
+
QuantumFunctionDeclaration,
|
30
|
+
)
|
31
|
+
from classiq.interface.model.quantum_lambda_function import (
|
32
|
+
OperandIdentifier,
|
33
|
+
QuantumLambdaFunction,
|
34
|
+
)
|
35
|
+
from classiq.interface.model.quantum_statement import QuantumStatement
|
36
|
+
|
37
|
+
from classiq.model_expansions.closure import (
|
38
|
+
Closure,
|
39
|
+
FunctionClosure,
|
40
|
+
)
|
41
|
+
from classiq.model_expansions.debug_flag import debug_mode
|
42
|
+
from classiq.model_expansions.evaluators.classical_expression import (
|
43
|
+
evaluate_classical_expression,
|
44
|
+
)
|
45
|
+
from classiq.model_expansions.expression_renamer import ExpressionRenamer
|
46
|
+
from classiq.model_expansions.function_builder import (
|
47
|
+
FunctionContext,
|
48
|
+
OperationBuilder,
|
49
|
+
OperationContext,
|
50
|
+
)
|
51
|
+
from classiq.model_expansions.scope import Evaluated, QuantumSymbol, Scope
|
52
|
+
from classiq.model_expansions.scope_initialization import (
|
53
|
+
add_constants_to_scope,
|
54
|
+
add_entry_point_params_to_scope,
|
55
|
+
get_main_renamer,
|
56
|
+
init_builtin_types,
|
57
|
+
init_top_level_scope,
|
58
|
+
)
|
59
|
+
from classiq.model_expansions.utils.counted_name_allocator import CountedNameAllocator
|
60
|
+
from classiq.model_expansions.visitors.variable_references import VarRefCollector
|
61
|
+
from classiq.qmod.builtins.enums import BUILTIN_ENUM_DECLARATIONS
|
62
|
+
from classiq.qmod.builtins.structs import BUILTIN_STRUCT_DECLARATIONS
|
63
|
+
from classiq.qmod.model_state_container import QMODULE
|
64
|
+
from classiq.qmod.semantics.error_manager import ErrorManager
|
65
|
+
|
66
|
+
|
67
|
+
class BaseInterpreter:
|
68
|
+
def __init__(self, model: Model) -> None:
|
69
|
+
self._model = model
|
70
|
+
self._top_level_scope = Scope()
|
71
|
+
self._counted_name_allocator = CountedNameAllocator()
|
72
|
+
self._builder = OperationBuilder(
|
73
|
+
self._top_level_scope, self._counted_name_allocator
|
74
|
+
)
|
75
|
+
self._expanded_functions: dict[str, NativeFunctionDefinition] = {}
|
76
|
+
|
77
|
+
init_builtin_types()
|
78
|
+
init_top_level_scope(model, self._top_level_scope)
|
79
|
+
self._functions_compilation_metadata: dict[str, CompilationMetadata] = dict(
|
80
|
+
self._model.functions_compilation_metadata
|
81
|
+
)
|
82
|
+
self._expanded_functions_compilation_metadata: dict[
|
83
|
+
str, CompilationMetadata
|
84
|
+
] = defaultdict(CompilationMetadata)
|
85
|
+
self._counted_name_allocator = CountedNameAllocator()
|
86
|
+
self._error_manager: ErrorManager = ErrorManager()
|
87
|
+
|
88
|
+
def get_main_renamer(self) -> Optional[ExpressionRenamer]:
|
89
|
+
return get_main_renamer(self._get_function_declarations())
|
90
|
+
|
91
|
+
def _expand_main_func(self) -> None:
|
92
|
+
main_closure = self._get_main_closure(
|
93
|
+
self._top_level_scope[MAIN_FUNCTION_NAME].value
|
94
|
+
)
|
95
|
+
add_entry_point_params_to_scope(
|
96
|
+
main_closure.positional_arg_declarations, main_closure
|
97
|
+
)
|
98
|
+
context = self._expand_operation(main_closure)
|
99
|
+
self._expanded_functions[main_closure.closure_id] = (
|
100
|
+
self._builder.create_definition(cast(FunctionContext, context))
|
101
|
+
)
|
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
|
+
|
113
|
+
def expand(self) -> Model:
|
114
|
+
try:
|
115
|
+
with self._error_manager.call("main"):
|
116
|
+
self._expand_main_func()
|
117
|
+
except Exception as e:
|
118
|
+
if isinstance(e, ClassiqInternalExpansionError) or debug_mode.get():
|
119
|
+
raise e
|
120
|
+
if not isinstance(e, (ClassiqError, ValidationError)):
|
121
|
+
raise ClassiqInternalExpansionError(str(e)) from None
|
122
|
+
prefix = ""
|
123
|
+
if not isinstance(e, ClassiqExpansionError):
|
124
|
+
prefix = f"{type(e).__name__}: "
|
125
|
+
self._error_manager.add_error(f"{prefix}{e}")
|
126
|
+
finally:
|
127
|
+
self._error_manager.report_errors(ClassiqExpansionError)
|
128
|
+
|
129
|
+
return Model(
|
130
|
+
constraints=self._model.constraints,
|
131
|
+
preferences=self._model.preferences,
|
132
|
+
classical_execution_code=self._model.classical_execution_code,
|
133
|
+
execution_preferences=self._model.execution_preferences,
|
134
|
+
functions=list(self._expanded_functions.values()),
|
135
|
+
constants=self._model.constants,
|
136
|
+
enums=[
|
137
|
+
enum_decl
|
138
|
+
for name, enum_decl in QMODULE.enum_decls.items()
|
139
|
+
if name not in BUILTIN_ENUM_DECLARATIONS
|
140
|
+
],
|
141
|
+
types=[
|
142
|
+
struct_decl
|
143
|
+
for name, struct_decl in QMODULE.type_decls.items()
|
144
|
+
if name not in BUILTIN_STRUCT_DECLARATIONS
|
145
|
+
],
|
146
|
+
qstructs=list(QMODULE.qstruct_decls.values()),
|
147
|
+
debug_info=self._model.debug_info,
|
148
|
+
functions_compilation_metadata=self._expanded_functions_compilation_metadata,
|
149
|
+
)
|
150
|
+
|
151
|
+
@singledispatchmethod
|
152
|
+
def evaluate(self, expression: Any) -> Evaluated:
|
153
|
+
raise NotImplementedError(f"Cannot evaluate {expression!r}")
|
154
|
+
|
155
|
+
@evaluate.register
|
156
|
+
def evaluate_classical_expression(self, expression: Expression) -> Evaluated:
|
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
|
168
|
+
|
169
|
+
@evaluate.register
|
170
|
+
def evaluate_identifier(self, identifier: str) -> Evaluated:
|
171
|
+
return self._builder.current_scope[identifier]
|
172
|
+
|
173
|
+
@evaluate.register
|
174
|
+
def _evaluate_lambda(self, function: QuantumLambdaFunction) -> Evaluated:
|
175
|
+
return self.evaluate_lambda(function)
|
176
|
+
|
177
|
+
def evaluate_lambda(self, function: QuantumLambdaFunction) -> Evaluated:
|
178
|
+
raise NotImplementedError
|
179
|
+
|
180
|
+
@evaluate.register
|
181
|
+
def evaluate_handle_binding(self, handle_binding: HandleBinding) -> Evaluated:
|
182
|
+
return self.evaluate(handle_binding.name)
|
183
|
+
|
184
|
+
@evaluate.register
|
185
|
+
def evaluate_sliced_handle_binding(
|
186
|
+
self, sliced_handle_binding: SlicedHandleBinding
|
187
|
+
) -> Evaluated:
|
188
|
+
quantum_variable = self.evaluate(sliced_handle_binding.base_handle).as_type(
|
189
|
+
QuantumSymbol
|
190
|
+
)
|
191
|
+
start = self.evaluate(sliced_handle_binding.start).as_type(int)
|
192
|
+
end = self.evaluate(sliced_handle_binding.end).as_type(int)
|
193
|
+
return Evaluated(value=quantum_variable[start:end])
|
194
|
+
|
195
|
+
@evaluate.register
|
196
|
+
def evaluate_list(self, value: list) -> Evaluated:
|
197
|
+
return Evaluated(value=[self.evaluate(arg).value for arg in value])
|
198
|
+
|
199
|
+
@evaluate.register
|
200
|
+
def evaluate_subscript_handle(self, subscript: SubscriptHandleBinding) -> Evaluated:
|
201
|
+
base_value = self.evaluate(subscript.base_handle)
|
202
|
+
index_value = self.evaluate(subscript.index).as_type(int)
|
203
|
+
return Evaluated(value=base_value.value[index_value])
|
204
|
+
|
205
|
+
@evaluate.register
|
206
|
+
def evaluate_subscript_operand(self, subscript: OperandIdentifier) -> Evaluated:
|
207
|
+
base_value = self.evaluate(subscript.name)
|
208
|
+
index_value = self.evaluate(subscript.index).as_type(int)
|
209
|
+
return Evaluated(value=base_value.value[index_value])
|
210
|
+
|
211
|
+
@evaluate.register
|
212
|
+
def evaluate_field_access(self, field_access: FieldHandleBinding) -> Evaluated:
|
213
|
+
base_value = self.evaluate(field_access.base_handle)
|
214
|
+
return Evaluated(value=base_value.value.fields[field_access.field])
|
215
|
+
|
216
|
+
@abstractmethod
|
217
|
+
def emit(self, statement: QuantumStatement) -> None:
|
218
|
+
pass
|
219
|
+
|
220
|
+
def _expand_block(self, block: Sequence[QuantumStatement], block_name: str) -> None:
|
221
|
+
with self._builder.block_context(block_name):
|
222
|
+
for statement in block:
|
223
|
+
self.emit_statement(statement)
|
224
|
+
|
225
|
+
def emit_statement(self, statement: QuantumStatement) -> None:
|
226
|
+
source_ref = statement.source_ref
|
227
|
+
error_context = (
|
228
|
+
self._error_manager.node_context(statement)
|
229
|
+
if source_ref is not None
|
230
|
+
else nullcontext()
|
231
|
+
)
|
232
|
+
with error_context, self._builder.source_ref_context(source_ref):
|
233
|
+
self.emit(statement)
|
234
|
+
|
235
|
+
def _expand_operation(self, operation: Closure) -> OperationContext:
|
236
|
+
with self._builder.operation_context(operation) as context:
|
237
|
+
if isinstance(operation, FunctionClosure) and (
|
238
|
+
(func_def := self._expanded_functions.get(operation.closure_id))
|
239
|
+
is not None
|
240
|
+
):
|
241
|
+
captured_vars = self._top_level_scope[func_def.name].value.captured_vars
|
242
|
+
operation.captured_vars.update(captured_vars)
|
243
|
+
else:
|
244
|
+
self._expand_body(operation)
|
245
|
+
|
246
|
+
return context
|
247
|
+
|
248
|
+
def _expand_body(self, operation: Closure) -> None:
|
249
|
+
for block, block_body in operation.blocks.items():
|
250
|
+
self._expand_block(block_body, block)
|
251
|
+
|
252
|
+
def _get_function_declarations(self) -> Sequence[QuantumFunctionDeclaration]:
|
253
|
+
return [
|
254
|
+
QuantumFunctionDeclaration(
|
255
|
+
name=func_closure.name,
|
256
|
+
positional_arg_declarations=func_closure.positional_arg_declarations,
|
257
|
+
)
|
258
|
+
for func in self._top_level_scope.values()
|
259
|
+
if isinstance(func_closure := func.value, FunctionClosure)
|
260
|
+
]
|
261
|
+
|
262
|
+
def add_constant(self, constant: Constant) -> None:
|
263
|
+
add_constants_to_scope([constant], self._top_level_scope)
|
@@ -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)
|