classiq 0.61.0__py3-none-any.whl → 0.63.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- classiq/__init__.py +3 -0
- classiq/_internals/api_wrapper.py +6 -26
- classiq/_internals/client.py +1 -9
- classiq/applications/chemistry/chemistry_model_constructor.py +1 -1
- classiq/applications/combinatorial_helpers/combinatorial_problem_utils.py +26 -8
- classiq/applications/combinatorial_helpers/optimization_model.py +13 -2
- classiq/applications/combinatorial_helpers/pyomo_utils.py +143 -13
- classiq/applications/combinatorial_optimization/combinatorial_optimization_model_constructor.py +1 -1
- classiq/applications/combinatorial_optimization/combinatorial_problem.py +58 -23
- classiq/applications/grover/grover_model_constructor.py +1 -1
- classiq/applications/libraries/qmci_library.py +2 -1
- classiq/execution/execution_session.py +66 -96
- classiq/execution/jobs.py +12 -10
- classiq/interface/_version.py +1 -1
- classiq/interface/backend/backend_preferences.py +26 -5
- classiq/interface/backend/pydantic_backend.py +1 -1
- classiq/interface/backend/quantum_backend_providers.py +3 -1
- classiq/interface/chemistry/operator.py +0 -204
- classiq/interface/execution/primitives.py +1 -0
- classiq/interface/generator/compiler_keywords.py +4 -0
- classiq/interface/generator/copy.py +47 -0
- classiq/interface/generator/function_param_list_without_self_reference.py +2 -0
- classiq/interface/generator/functions/type_name.py +6 -0
- classiq/interface/generator/generated_circuit_data.py +22 -7
- classiq/interface/generator/model/model.py +3 -0
- classiq/interface/generator/model/preferences/preferences.py +14 -1
- classiq/interface/generator/quantum_function_call.py +4 -2
- classiq/interface/generator/types/compilation_metadata.py +2 -1
- classiq/interface/model/handle_binding.py +50 -5
- classiq/interface/model/quantum_type.py +16 -0
- classiq/interface/server/routes.py +1 -3
- classiq/model_expansions/capturing/captured_vars.py +114 -28
- classiq/model_expansions/closure.py +25 -65
- classiq/model_expansions/function_builder.py +19 -9
- classiq/model_expansions/generative_functions.py +16 -2
- classiq/model_expansions/interpreter.py +110 -66
- classiq/model_expansions/model_tables.py +4 -0
- classiq/model_expansions/quantum_operations/call_emitter.py +83 -20
- classiq/model_expansions/quantum_operations/classicalif.py +1 -1
- classiq/model_expansions/quantum_operations/control.py +3 -10
- classiq/model_expansions/quantum_operations/emitter.py +3 -4
- classiq/model_expansions/quantum_operations/quantum_assignment_operation.py +1 -2
- classiq/model_expansions/quantum_operations/quantum_function_call.py +1 -1
- classiq/model_expansions/quantum_operations/repeat.py +4 -3
- classiq/model_expansions/quantum_operations/shallow_emitter.py +9 -3
- classiq/model_expansions/scope.py +9 -13
- classiq/model_expansions/scope_initialization.py +34 -25
- classiq/model_expansions/transformers/var_splitter.py +57 -7
- classiq/open_library/__init__.py +4 -0
- classiq/open_library/functions/__init__.py +130 -0
- classiq/{qmod/builtins → open_library}/functions/amplitude_estimation.py +2 -2
- classiq/{qmod/builtins → open_library}/functions/discrete_sine_cosine_transform.py +6 -4
- classiq/{qmod/builtins → open_library}/functions/grover.py +2 -2
- classiq/{qmod/builtins → open_library}/functions/linear_pauli_rotation.py +1 -1
- classiq/{qmod/builtins → open_library}/functions/modular_exponentiation.py +2 -2
- classiq/{qmod/builtins → open_library}/functions/qpe.py +2 -2
- classiq/{qmod/builtins → open_library}/functions/state_preparation.py +6 -149
- classiq/{qmod/builtins → open_library}/functions/swap_test.py +1 -1
- classiq/open_library/functions/utility_functions.py +81 -0
- classiq/{qmod/builtins → open_library}/functions/variational.py +1 -1
- classiq/qmod/builtins/functions/__init__.py +4 -130
- classiq/qmod/builtins/functions/allocation.py +150 -0
- classiq/qmod/builtins/functions/arithmetic.py +0 -34
- classiq/qmod/builtins/functions/operators.py +0 -6
- classiq/qmod/builtins/operations.py +19 -80
- classiq/qmod/create_model_function.py +8 -162
- classiq/qmod/generative.py +0 -16
- classiq/qmod/model_state_container.py +7 -0
- classiq/qmod/native/pretty_printer.py +10 -11
- classiq/qmod/pretty_print/pretty_printer.py +1 -1
- classiq/qmod/python_classical_type.py +1 -5
- classiq/qmod/qfunc.py +11 -12
- classiq/qmod/qmod_variable.py +1 -3
- classiq/qmod/quantum_expandable.py +23 -1
- classiq/qmod/quantum_function.py +69 -7
- {classiq-0.61.0.dist-info → classiq-0.63.0.dist-info}/METADATA +2 -1
- {classiq-0.61.0.dist-info → classiq-0.63.0.dist-info}/RECORD +82 -78
- classiq/qmod/builtins/functions/utility_functions.py +0 -43
- /classiq/{qmod/builtins → open_library}/functions/hea.py +0 -0
- /classiq/{qmod/builtins → open_library}/functions/qaoa_penalty.py +0 -0
- /classiq/{qmod/builtins → open_library}/functions/qft_functions.py +0 -0
- /classiq/{qmod/builtins → open_library}/functions/qsvt.py +0 -0
- {classiq-0.61.0.dist-info → classiq-0.63.0.dist-info}/WHEEL +0 -0
@@ -8,6 +8,9 @@ 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
|
+
)
|
11
14
|
from classiq.interface.generator.generated_circuit_data import OperationLevel
|
12
15
|
from classiq.interface.model.classical_parameter_declaration import (
|
13
16
|
ClassicalParameterDeclaration,
|
@@ -20,6 +23,10 @@ from classiq.interface.model.quantum_function_declaration import (
|
|
20
23
|
NamedParamsQuantumFunctionDeclaration,
|
21
24
|
PositionalArg,
|
22
25
|
)
|
26
|
+
from classiq.interface.model.quantum_lambda_function import (
|
27
|
+
OperandIdentifier,
|
28
|
+
QuantumLambdaFunction,
|
29
|
+
)
|
23
30
|
from classiq.interface.model.quantum_statement import QuantumStatement
|
24
31
|
from classiq.interface.model.variable_declaration_statement import (
|
25
32
|
VariableDeclarationStatement,
|
@@ -28,7 +35,7 @@ from classiq.interface.model.variable_declaration_statement import (
|
|
28
35
|
from classiq.model_expansions.capturing.captured_vars import (
|
29
36
|
validate_args_are_not_propagated,
|
30
37
|
)
|
31
|
-
from classiq.model_expansions.closure import FunctionClosure
|
38
|
+
from classiq.model_expansions.closure import FunctionClosure, GenerativeClosure
|
32
39
|
from classiq.model_expansions.evaluators.argument_types import (
|
33
40
|
add_information_from_output_arguments,
|
34
41
|
)
|
@@ -45,6 +52,7 @@ from classiq.model_expansions.quantum_operations.emitter import (
|
|
45
52
|
from classiq.model_expansions.scope import Evaluated, QuantumSymbol, Scope
|
46
53
|
from classiq.model_expansions.transformers.var_splitter import VarSplitter
|
47
54
|
from classiq.qmod.builtins.functions import allocate, free
|
55
|
+
from classiq.qmod.model_state_container import QMODULE
|
48
56
|
|
49
57
|
if TYPE_CHECKING:
|
50
58
|
from classiq.model_expansions.interpreter import Interpreter
|
@@ -53,7 +61,7 @@ if TYPE_CHECKING:
|
|
53
61
|
class CallEmitter(Generic[QuantumStatementT], Emitter[QuantumStatementT], VarSplitter):
|
54
62
|
def __init__(self, interpreter: "Interpreter") -> None:
|
55
63
|
Emitter.__init__(self, interpreter)
|
56
|
-
VarSplitter.__init__(self, interpreter.
|
64
|
+
VarSplitter.__init__(self, interpreter._builder.current_scope)
|
57
65
|
|
58
66
|
@staticmethod
|
59
67
|
def _should_wrap(body: Sequence[QuantumStatement]) -> bool:
|
@@ -65,7 +73,7 @@ class CallEmitter(Generic[QuantumStatementT], Emitter[QuantumStatementT], VarSpl
|
|
65
73
|
self, name: str, body: Sequence[QuantumStatement]
|
66
74
|
) -> QuantumFunctionCall:
|
67
75
|
wrapping_function = FunctionClosure.create(
|
68
|
-
name=name,
|
76
|
+
name=self._counted_name_allocator.allocate(name),
|
69
77
|
body=body,
|
70
78
|
scope=Scope(parent=self._current_scope),
|
71
79
|
is_lambda=True,
|
@@ -90,14 +98,21 @@ class CallEmitter(Generic[QuantumStatementT], Emitter[QuantumStatementT], VarSpl
|
|
90
98
|
args: list[ArgValue],
|
91
99
|
propagated_debug_info: Optional[FunctionDebugInfo] = None,
|
92
100
|
) -> QuantumFunctionCall:
|
101
|
+
function = function.clone()
|
93
102
|
function = function.set_depth(self._builder.current_function.depth + 1)
|
94
|
-
function = function.copy_scope()
|
95
103
|
evaluated_args = [self._interpreter.evaluate(arg) for arg in args]
|
96
104
|
new_declaration = self._prepare_fully_typed_declaration(
|
97
105
|
function, evaluated_args
|
98
106
|
)
|
99
107
|
new_positional_arg_decls = new_declaration.positional_arg_declarations
|
100
108
|
is_atomic = function.is_atomic
|
109
|
+
if (
|
110
|
+
self._interpreter._is_shallow
|
111
|
+
and self._is_function_purely_declarative(function)
|
112
|
+
and self._are_args_purely_declarative(args)
|
113
|
+
):
|
114
|
+
is_atomic = True
|
115
|
+
self._interpreter.add_purely_declarative_function(function)
|
101
116
|
new_function_name = function.name
|
102
117
|
if not is_atomic: # perform monomorphization per interpreted parameters set
|
103
118
|
self._add_params_to_scope(
|
@@ -115,15 +130,20 @@ class CallEmitter(Generic[QuantumStatementT], Emitter[QuantumStatementT], VarSpl
|
|
115
130
|
self._top_level_scope[function_def.name] = Evaluated(
|
116
131
|
value=function_context.closure.with_new_declaration(function_def)
|
117
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
|
+
|
118
145
|
new_declaration = function_def
|
119
146
|
new_function_name = function_def.name
|
120
|
-
compilation_metadata = self._functions_compilation_metadata.get(
|
121
|
-
function.name
|
122
|
-
)
|
123
|
-
if compilation_metadata is not None:
|
124
|
-
self._expanded_functions_compilation_metadata[new_function_name] = (
|
125
|
-
compilation_metadata
|
126
|
-
)
|
127
147
|
|
128
148
|
new_positional_args = self._get_new_positional_args(
|
129
149
|
evaluated_args, is_atomic, new_positional_arg_decls
|
@@ -239,13 +259,56 @@ class CallEmitter(Generic[QuantumStatementT], Emitter[QuantumStatementT], VarSpl
|
|
239
259
|
different from the call scope. For example, the former uses r,s and the latter
|
240
260
|
uses p, q.
|
241
261
|
"""
|
242
|
-
|
243
|
-
|
244
|
-
|
245
|
-
|
246
|
-
|
247
|
-
|
248
|
-
|
249
|
-
|
250
|
-
|
262
|
+
# The signature scope is passed as a separate argument to avoid contaminating the statement execution scope
|
263
|
+
return NamedParamsQuantumFunctionDeclaration(
|
264
|
+
name=function.name,
|
265
|
+
positional_arg_declarations=evaluate_parameter_types_from_args(
|
266
|
+
function,
|
267
|
+
function.signature_scope,
|
268
|
+
evaluated_args,
|
269
|
+
),
|
270
|
+
)
|
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
|
+
)
|
251
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
|
+
)
|
@@ -45,7 +45,7 @@ class ClassicalIfEmitter(CallEmitter[ClassicalIf]):
|
|
45
45
|
return
|
46
46
|
|
47
47
|
then_else_func = FunctionClosure.create(
|
48
|
-
name=
|
48
|
+
name=self._counted_name_allocator.allocate("then" if condition else "else"),
|
49
49
|
body=body,
|
50
50
|
scope=Scope(parent=self._current_scope),
|
51
51
|
is_lambda=True,
|
@@ -1,5 +1,3 @@
|
|
1
|
-
from typing import cast
|
2
|
-
|
3
1
|
from sympy import Equality
|
4
2
|
from sympy.logic.boolalg import Boolean
|
5
3
|
from typing_extensions import TypeGuard
|
@@ -55,6 +53,9 @@ from classiq.qmod.builtins.functions.standard_gates import X
|
|
55
53
|
|
56
54
|
class ControlEmitter(ExpressionOperationEmitter[Control]):
|
57
55
|
def emit(self, control: Control, /) -> None:
|
56
|
+
validate_args_are_not_propagated(
|
57
|
+
extract_handles(control.expression), extract_handles(control.body)
|
58
|
+
)
|
58
59
|
condition = control.expression
|
59
60
|
arrays_with_subscript = self.split_symbols(
|
60
61
|
condition, self._counted_name_allocator.allocate
|
@@ -117,10 +118,6 @@ class ControlEmitter(ExpressionOperationEmitter[Control]):
|
|
117
118
|
scope=Scope(parent=self._current_scope),
|
118
119
|
)
|
119
120
|
context = self._expand_operation(control_operation)
|
120
|
-
validate_args_are_not_propagated(
|
121
|
-
control.var_handles,
|
122
|
-
extract_handles([block.statements for block in context.blocks.values()]),
|
123
|
-
)
|
124
121
|
self._update_control_state(control)
|
125
122
|
self.emit_statement(
|
126
123
|
control.model_copy(update=dict(body=context.statements("body")))
|
@@ -130,10 +127,6 @@ class ControlEmitter(ExpressionOperationEmitter[Control]):
|
|
130
127
|
wrapping_function = self._create_expanded_wrapping_function(
|
131
128
|
CONTROL_OPERATOR_NAME, control.body
|
132
129
|
)
|
133
|
-
validate_args_are_not_propagated(
|
134
|
-
control.var_handles,
|
135
|
-
cast(list[HandleBinding], wrapping_function.positional_args),
|
136
|
-
)
|
137
130
|
self._update_control_state(control)
|
138
131
|
self.emit_statement(control.model_copy(update=dict(body=[wrapping_function])))
|
139
132
|
|
@@ -49,13 +49,12 @@ class Emitter(Generic[QuantumStatementT]):
|
|
49
49
|
def __init__(self, interpreter: "Interpreter") -> None:
|
50
50
|
self._interpreter = interpreter
|
51
51
|
|
52
|
-
self._scope_guard = self._interpreter._scope_guard
|
53
52
|
self._machine_precision = self._interpreter._model.preferences.machine_precision
|
54
53
|
self._expanded_functions_compilation_metadata = (
|
55
54
|
self._interpreter._expanded_functions_compilation_metadata
|
56
55
|
)
|
57
56
|
self._functions_compilation_metadata = (
|
58
|
-
self._interpreter.
|
57
|
+
self._interpreter._functions_compilation_metadata
|
59
58
|
)
|
60
59
|
|
61
60
|
@abstractmethod
|
@@ -71,7 +70,7 @@ class Emitter(Generic[QuantumStatementT]):
|
|
71
70
|
|
72
71
|
@property
|
73
72
|
def _current_scope(self) -> Scope:
|
74
|
-
return self.
|
73
|
+
return self._builder.current_scope
|
75
74
|
|
76
75
|
@property
|
77
76
|
def _top_level_scope(self) -> Scope:
|
@@ -104,7 +103,7 @@ class Emitter(Generic[QuantumStatementT]):
|
|
104
103
|
)
|
105
104
|
gen_closure = GenerativeClosure(
|
106
105
|
name=func_decl.name,
|
107
|
-
scope=Scope(parent=self._interpreter.
|
106
|
+
scope=Scope(parent=self._interpreter._builder.current_scope),
|
108
107
|
blocks={},
|
109
108
|
generative_blocks={
|
110
109
|
block_name: GenerativeQFunc(
|
@@ -123,8 +123,7 @@ class QuantumAssignmentOperationEmitter(
|
|
123
123
|
self, op: ArithmeticOperation
|
124
124
|
) -> tuple[ArithmeticOperation, Expression, bool]:
|
125
125
|
if (
|
126
|
-
|
127
|
-
or op.operation_kind
|
126
|
+
op.operation_kind
|
128
127
|
not in (
|
129
128
|
ArithmeticOperationKind.Assignment,
|
130
129
|
ArithmeticOperationKind.InplaceXor,
|
@@ -18,7 +18,7 @@ class QuantumFunctionCallEmitter(CallEmitter[QuantumFunctionCall]):
|
|
18
18
|
def emit(self, call: QuantumFunctionCall, /) -> None:
|
19
19
|
function = self._interpreter.evaluate(call.function).as_type(FunctionClosure)
|
20
20
|
args = call.positional_args
|
21
|
-
with ErrorManager().call(function.name)
|
21
|
+
with ErrorManager().call(function.name):
|
22
22
|
self._emit_quantum_function_call(
|
23
23
|
function, args, self._debug_info.get(call.uuid)
|
24
24
|
)
|
@@ -22,10 +22,11 @@ class RepeatEmitter(CallEmitter[Repeat]):
|
|
22
22
|
raise ClassiqExpansionError(
|
23
23
|
f"repeat count must be non-negative, got {count}"
|
24
24
|
)
|
25
|
+
op_name = self._counted_name_allocator.allocate(REPEAT_OPERATOR_NAME)
|
25
26
|
for i in range(count):
|
26
|
-
self._emit_iteration(repeat, i)
|
27
|
+
self._emit_iteration(repeat, i, op_name)
|
27
28
|
|
28
|
-
def _emit_iteration(self, repeat: Repeat, i: int) -> None:
|
29
|
+
def _emit_iteration(self, repeat: Repeat, i: int, op_name: str) -> None:
|
29
30
|
closure_constructor: type[FunctionClosure]
|
30
31
|
extra_args: dict
|
31
32
|
if repeat.is_generative():
|
@@ -41,7 +42,7 @@ class RepeatEmitter(CallEmitter[Repeat]):
|
|
41
42
|
closure_constructor = FunctionClosure
|
42
43
|
extra_args = {}
|
43
44
|
iteration_function = closure_constructor.create(
|
44
|
-
name=
|
45
|
+
name=op_name,
|
45
46
|
positional_arg_declarations=[
|
46
47
|
ClassicalParameterDeclaration(
|
47
48
|
name=repeat.iter_var, classical_type=Integer()
|
@@ -11,6 +11,9 @@ from classiq.interface.model.quantum_expressions.arithmetic_operation import (
|
|
11
11
|
ArithmeticOperation,
|
12
12
|
ArithmeticOperationKind,
|
13
13
|
)
|
14
|
+
from classiq.interface.model.quantum_expressions.quantum_expression import (
|
15
|
+
QuantumAssignmentOperation,
|
16
|
+
)
|
14
17
|
from classiq.interface.model.quantum_statement import QuantumOperation, QuantumStatement
|
15
18
|
|
16
19
|
from classiq.model_expansions.closure import Closure
|
@@ -68,12 +71,15 @@ class ShallowEmitter(Emitter[QuantumOperation]):
|
|
68
71
|
).value.handle
|
69
72
|
|
70
73
|
op = op.model_copy(update=expanded_components)
|
71
|
-
if isinstance(op,
|
74
|
+
if isinstance(op, QuantumAssignmentOperation):
|
72
75
|
self._post_process_assignment(op)
|
73
76
|
self._builder.emit_statement(op)
|
74
77
|
|
75
|
-
def _post_process_assignment(self, op:
|
76
|
-
if
|
78
|
+
def _post_process_assignment(self, op: QuantumAssignmentOperation) -> None:
|
79
|
+
if (
|
80
|
+
isinstance(op, ArithmeticOperation)
|
81
|
+
and op.operation_kind == ArithmeticOperationKind.Assignment
|
82
|
+
):
|
77
83
|
direction = PortDeclarationDirection.Output
|
78
84
|
self._update_result_type(op)
|
79
85
|
else:
|
@@ -2,7 +2,6 @@ import itertools
|
|
2
2
|
import re
|
3
3
|
from collections import UserDict
|
4
4
|
from collections.abc import Iterator
|
5
|
-
from contextlib import contextmanager
|
6
5
|
from dataclasses import dataclass
|
7
6
|
from functools import singledispatch
|
8
7
|
from typing import TYPE_CHECKING, Any, Optional, TypeVar, Union
|
@@ -164,8 +163,14 @@ class Evaluated: # FIXME: Merge with EvaluatedExpression if possible
|
|
164
163
|
return int(self.value)
|
165
164
|
|
166
165
|
def emit(self) -> ArgValue:
|
167
|
-
|
166
|
+
from classiq.model_expansions.closure import FunctionClosure
|
167
|
+
|
168
|
+
if isinstance(self.value, (QuantumSymbol, FunctionClosure)):
|
168
169
|
return self.value.emit()
|
170
|
+
if isinstance(self.value, list) and all(
|
171
|
+
isinstance(item, FunctionClosure) for item in self.value
|
172
|
+
):
|
173
|
+
return [item.emit() for item in self.value]
|
169
174
|
|
170
175
|
ret = Expression(expr=evaluated_to_str(self.value))
|
171
176
|
ret._evaluated_expr = EvaluatedExpression(value=self.value)
|
@@ -231,14 +236,5 @@ class Scope(EvaluatedUserDict):
|
|
231
236
|
parent=parent,
|
232
237
|
)
|
233
238
|
|
234
|
-
def
|
235
|
-
return Scope(
|
236
|
-
self.data, parent=None if self._parent is None else self._parent.copy()
|
237
|
-
)
|
238
|
-
|
239
|
-
@contextmanager
|
240
|
-
def freeze(self) -> Iterator[None]:
|
241
|
-
previous = self._copy()
|
242
|
-
yield
|
243
|
-
self.data = previous.data
|
244
|
-
self._parent = previous._parent
|
239
|
+
def clone(self) -> "Scope":
|
240
|
+
return Scope(self.data, parent=self._parent)
|
@@ -1,4 +1,5 @@
|
|
1
1
|
from collections.abc import Sequence
|
2
|
+
from typing import TYPE_CHECKING
|
2
3
|
|
3
4
|
from classiq.interface.exceptions import ClassiqError
|
4
5
|
from classiq.interface.generator.constant import Constant
|
@@ -12,7 +13,11 @@ from classiq.interface.model.handle_binding import HandleBinding
|
|
12
13
|
from classiq.interface.model.model import MAIN_FUNCTION_NAME, Model
|
13
14
|
from classiq.interface.model.native_function_definition import NativeFunctionDefinition
|
14
15
|
from classiq.interface.model.port_declaration import PortDeclaration
|
15
|
-
from classiq.interface.model.quantum_function_declaration import
|
16
|
+
from classiq.interface.model.quantum_function_declaration import (
|
17
|
+
NamedParamsQuantumFunctionDeclaration,
|
18
|
+
PositionalArg,
|
19
|
+
QuantumFunctionDeclaration,
|
20
|
+
)
|
16
21
|
|
17
22
|
from classiq.model_expansions.closure import FunctionClosure, GenerativeFunctionClosure
|
18
23
|
from classiq.model_expansions.evaluators.classical_expression import (
|
@@ -32,12 +37,14 @@ from classiq.qmod.quantum_function import GenerativeQFunc
|
|
32
37
|
|
33
38
|
|
34
39
|
def get_main_renamer(
|
35
|
-
|
40
|
+
func_decls: Sequence[QuantumFunctionDeclaration],
|
36
41
|
) -> ExpressionRenamer:
|
37
|
-
for
|
38
|
-
if
|
42
|
+
for func_decl in func_decls:
|
43
|
+
if func_decl.name == MAIN_FUNCTION_NAME:
|
44
|
+
if TYPE_CHECKING:
|
45
|
+
assert isinstance(func_decl, NamedParamsQuantumFunctionDeclaration)
|
39
46
|
return ExpressionRenamer.from_positional_arg_declarations(
|
40
|
-
|
47
|
+
func_decl.positional_arg_declarations, CPARAM_EXECUTION_SUFFIX
|
41
48
|
)
|
42
49
|
return ExpressionRenamer(var_mapping={})
|
43
50
|
|
@@ -49,32 +56,34 @@ def add_constants_to_scope(constants: list[Constant], scope: Scope) -> None:
|
|
49
56
|
)
|
50
57
|
|
51
58
|
|
52
|
-
def
|
53
|
-
functions:
|
59
|
+
def add_functions_to_scope(
|
60
|
+
functions: Sequence[NativeFunctionDefinition], scope: Scope
|
54
61
|
) -> None:
|
55
62
|
for function in functions:
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
63
|
+
if function.name not in scope:
|
64
|
+
scope[function.name] = Evaluated(
|
65
|
+
value=FunctionClosure.create(
|
66
|
+
name=function.name,
|
67
|
+
positional_arg_declarations=function.positional_arg_declarations,
|
68
|
+
body=function.body,
|
69
|
+
scope=Scope(parent=scope),
|
70
|
+
)
|
62
71
|
)
|
63
|
-
)
|
64
72
|
|
65
73
|
|
66
|
-
def
|
67
|
-
functions:
|
74
|
+
def add_generative_functions_to_scope(
|
75
|
+
functions: Sequence[GenerativeQFunc], scope: Scope
|
68
76
|
) -> None:
|
69
77
|
for function in functions:
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
78
|
+
if function.func_decl.name not in scope:
|
79
|
+
scope[function.func_decl.name] = Evaluated(
|
80
|
+
value=GenerativeFunctionClosure.create(
|
81
|
+
name=function.func_decl.name,
|
82
|
+
positional_arg_declarations=function.func_decl.positional_arg_declarations,
|
83
|
+
scope=Scope(parent=scope),
|
84
|
+
generative_blocks={"body": function},
|
85
|
+
)
|
76
86
|
)
|
77
|
-
)
|
78
87
|
|
79
88
|
|
80
89
|
def _init_builtins_scope(scope: Scope) -> None:
|
@@ -129,7 +138,7 @@ def add_entry_point_params_to_scope(
|
|
129
138
|
def init_top_level_scope(
|
130
139
|
model: Model, generative_functions: list[GenerativeQFunc], scope: Scope
|
131
140
|
) -> None:
|
132
|
-
|
133
|
-
|
141
|
+
add_generative_functions_to_scope(generative_functions, scope)
|
142
|
+
add_functions_to_scope(model.functions, scope)
|
134
143
|
add_constants_to_scope(model.constants, scope)
|
135
144
|
_init_builtins_scope(scope)
|
@@ -1,7 +1,7 @@
|
|
1
1
|
import ast
|
2
2
|
from dataclasses import dataclass
|
3
3
|
from itertools import chain
|
4
|
-
from typing import TYPE_CHECKING, Callable, TypeVar, cast
|
4
|
+
from typing import TYPE_CHECKING, Callable, Optional, TypeVar, cast
|
5
5
|
|
6
6
|
from classiq.interface.exceptions import (
|
7
7
|
ClassiqExpansionError,
|
@@ -14,6 +14,7 @@ from classiq.interface.model.handle_binding import (
|
|
14
14
|
HandleBinding,
|
15
15
|
NestedHandleBinding,
|
16
16
|
SlicedHandleBinding,
|
17
|
+
SubscriptHandleBinding,
|
17
18
|
)
|
18
19
|
from classiq.interface.model.quantum_expressions.quantum_expression import (
|
19
20
|
QuantumExpressionOperation,
|
@@ -125,12 +126,7 @@ class VarSplitter:
|
|
125
126
|
raise ClassiqExpansionError(
|
126
127
|
f"Could not determine the length of quantum array " f"{symbol.handle}."
|
127
128
|
)
|
128
|
-
target_slices =
|
129
|
-
target_part.start.to_int_value(): target_part.end.to_int_value()
|
130
|
-
for target_part in target_parts
|
131
|
-
if isinstance(target_part, SlicedHandleBinding)
|
132
|
-
and symbol.handle == target_part.base_handle
|
133
|
-
}
|
129
|
+
target_slices = self._get_target_slices(symbol, target_parts)
|
134
130
|
|
135
131
|
symbol_parts: list[QuantumSymbol] = []
|
136
132
|
idx = 0
|
@@ -151,6 +147,60 @@ class VarSplitter:
|
|
151
147
|
|
152
148
|
return symbol_parts
|
153
149
|
|
150
|
+
def _get_target_slices(
|
151
|
+
self, symbol: QuantumSymbol, target_parts: list[HandleBinding]
|
152
|
+
) -> dict[int, int]:
|
153
|
+
if TYPE_CHECKING:
|
154
|
+
assert isinstance(symbol.quantum_type, QuantumBitvector)
|
155
|
+
target_items = {
|
156
|
+
idx
|
157
|
+
for idx in range(symbol.quantum_type.length_value)
|
158
|
+
for target_part in target_parts
|
159
|
+
if target_part
|
160
|
+
in SubscriptHandleBinding(
|
161
|
+
base_handle=symbol.handle, index=Expression(expr=str(idx))
|
162
|
+
)
|
163
|
+
}
|
164
|
+
target_slices = {
|
165
|
+
target_part.start.to_int_value(): target_part.end.to_int_value()
|
166
|
+
for target_part in target_parts
|
167
|
+
if isinstance(target_part, SlicedHandleBinding)
|
168
|
+
and symbol.handle == target_part.base_handle
|
169
|
+
}
|
170
|
+
self._add_unused_indices_as_slices(symbol, target_items, target_slices)
|
171
|
+
return target_slices
|
172
|
+
|
173
|
+
@staticmethod
|
174
|
+
def _add_unused_indices_as_slices(
|
175
|
+
symbol: QuantumSymbol, target_items: set[int], target_slices: dict[int, int]
|
176
|
+
) -> None:
|
177
|
+
if TYPE_CHECKING:
|
178
|
+
assert isinstance(symbol.quantum_type, QuantumBitvector)
|
179
|
+
last_unused_idx: Optional[int] = None
|
180
|
+
array_length = symbol.quantum_type.length_value
|
181
|
+
idx = 0
|
182
|
+
|
183
|
+
while idx < array_length:
|
184
|
+
if (
|
185
|
+
idx in target_items or idx in target_slices
|
186
|
+
) and last_unused_idx is not None:
|
187
|
+
target_slices[last_unused_idx] = idx
|
188
|
+
last_unused_idx = None
|
189
|
+
|
190
|
+
if idx in target_slices:
|
191
|
+
if target_slices[idx] <= idx:
|
192
|
+
raise ClassiqInternalExpansionError
|
193
|
+
idx = target_slices[idx]
|
194
|
+
continue
|
195
|
+
|
196
|
+
if idx not in target_items and last_unused_idx is None:
|
197
|
+
last_unused_idx = idx
|
198
|
+
|
199
|
+
idx += 1
|
200
|
+
|
201
|
+
if last_unused_idx is not None:
|
202
|
+
target_slices[last_unused_idx] = array_length
|
203
|
+
|
154
204
|
def _get_struct_parts(
|
155
205
|
self, symbol: QuantumSymbol, target_parts: list[HandleBinding]
|
156
206
|
) -> list[QuantumSymbol]:
|