classiq 0.60.1__py3-none-any.whl → 0.62.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 +2 -0
- classiq/_internals/client.py +6 -1
- classiq/applications/__init__.py +1 -1
- classiq/applications/chemistry/__init__.py +7 -7
- classiq/applications/chemistry/chemistry_model_constructor.py +17 -6
- classiq/applications/combinatorial_helpers/optimization_model.py +9 -2
- classiq/applications/combinatorial_helpers/pyomo_utils.py +60 -9
- classiq/applications/combinatorial_optimization/__init__.py +7 -1
- classiq/applications/combinatorial_optimization/combinatorial_optimization_model_constructor.py +2 -0
- classiq/applications/combinatorial_optimization/combinatorial_problem.py +230 -0
- classiq/applications/finance/finance_model_constructor.py +6 -6
- classiq/applications/grover/grover_model_constructor.py +3 -0
- classiq/applications/libraries/qmci_library.py +1 -10
- classiq/applications/qnn/__init__.py +1 -1
- classiq/applications/qnn/datasets/__init__.py +8 -8
- classiq/applications/qsvm/qsvm.py +1 -1
- classiq/execution/__init__.py +0 -2
- classiq/execution/execution_session.py +6 -0
- classiq/execution/jobs.py +9 -1
- classiq/executor.py +1 -1
- classiq/interface/_version.py +1 -1
- classiq/interface/backend/backend_preferences.py +33 -15
- classiq/interface/backend/quantum_backend_providers.py +3 -1
- classiq/interface/executor/execution_preferences.py +1 -1
- classiq/interface/generator/application_apis/chemistry_declarations.py +1 -1
- classiq/interface/generator/application_apis/finance_declarations.py +2 -2
- classiq/interface/generator/arith/arithmetic.py +16 -1
- classiq/interface/generator/arith/arithmetic_expression_validator.py +4 -3
- classiq/interface/generator/copy.py +47 -0
- classiq/interface/generator/expressions/expression_constants.py +3 -0
- classiq/interface/generator/function_param_list_without_self_reference.py +2 -0
- classiq/interface/generator/generated_circuit_data.py +58 -20
- classiq/interface/generator/model/__init__.py +1 -1
- classiq/interface/generator/model/preferences/preferences.py +1 -1
- classiq/interface/generator/model/quantum_register.py +3 -3
- classiq/interface/generator/standard_gates/controlled_standard_gates.py +20 -32
- classiq/interface/generator/types/compilation_metadata.py +2 -1
- classiq/interface/ide/visual_model.py +1 -0
- classiq/interface/interface_version.py +1 -1
- classiq/interface/model/model.py +2 -3
- classiq/interface/model/quantum_function_call.py +4 -7
- classiq/interface/model/quantum_function_declaration.py +7 -0
- classiq/interface/model/quantum_lambda_function.py +10 -1
- classiq/interface/model/quantum_type.py +3 -1
- classiq/model_expansions/atomic_expression_functions_defs.py +3 -1
- classiq/model_expansions/capturing/captured_vars.py +36 -17
- classiq/model_expansions/capturing/mangling_utils.py +23 -15
- classiq/model_expansions/closure.py +6 -9
- classiq/model_expansions/evaluators/arg_type_match.py +7 -7
- classiq/model_expansions/expression_evaluator.py +5 -2
- classiq/model_expansions/function_builder.py +26 -4
- classiq/model_expansions/generative_functions.py +13 -91
- classiq/model_expansions/interpreter.py +75 -46
- classiq/model_expansions/quantum_operations/call_emitter.py +42 -29
- classiq/model_expansions/quantum_operations/classicalif.py +1 -1
- classiq/model_expansions/quantum_operations/control.py +5 -31
- classiq/model_expansions/quantum_operations/emitter.py +29 -17
- classiq/model_expansions/quantum_operations/expression_operation.py +3 -5
- classiq/model_expansions/quantum_operations/inplace_binary_operation.py +57 -15
- classiq/model_expansions/quantum_operations/invert.py +1 -6
- classiq/model_expansions/quantum_operations/phase.py +2 -5
- classiq/model_expansions/quantum_operations/power.py +0 -4
- classiq/model_expansions/quantum_operations/quantum_assignment_operation.py +19 -30
- classiq/model_expansions/quantum_operations/quantum_function_call.py +4 -2
- classiq/model_expansions/quantum_operations/shallow_emitter.py +161 -0
- classiq/model_expansions/quantum_operations/within_apply.py +0 -14
- classiq/model_expansions/scope.py +12 -16
- classiq/model_expansions/scope_initialization.py +0 -11
- classiq/model_expansions/sympy_conversion/expression_to_sympy.py +7 -0
- classiq/model_expansions/sympy_conversion/sympy_to_python.py +12 -2
- classiq/model_expansions/transformers/ast_renamer.py +26 -0
- classiq/model_expansions/transformers/var_splitter.py +11 -12
- classiq/model_expansions/visitors/variable_references.py +20 -12
- classiq/qmod/builtins/classical_execution_primitives.py +6 -6
- classiq/qmod/builtins/classical_functions.py +10 -10
- classiq/qmod/builtins/functions/__init__.py +89 -103
- classiq/qmod/builtins/functions/amplitude_estimation.py +1 -1
- classiq/qmod/builtins/functions/arithmetic.py +1 -1
- classiq/qmod/builtins/functions/discrete_sine_cosine_transform.py +6 -6
- classiq/qmod/builtins/functions/grover.py +5 -5
- classiq/qmod/builtins/functions/hea.py +1 -1
- classiq/qmod/builtins/functions/linear_pauli_rotation.py +2 -2
- classiq/qmod/builtins/functions/modular_exponentiation.py +8 -8
- classiq/qmod/builtins/functions/operators.py +1 -1
- classiq/qmod/builtins/functions/qaoa_penalty.py +5 -5
- classiq/qmod/builtins/functions/qft_functions.py +2 -2
- classiq/qmod/builtins/functions/qpe.py +9 -12
- classiq/qmod/builtins/functions/qsvt.py +177 -15
- classiq/qmod/builtins/functions/state_preparation.py +9 -9
- classiq/qmod/builtins/functions/swap_test.py +1 -1
- classiq/qmod/builtins/functions/utility_functions.py +2 -2
- classiq/qmod/builtins/functions/variational.py +2 -2
- classiq/qmod/builtins/operations.py +22 -83
- classiq/qmod/builtins/structs.py +9 -9
- classiq/qmod/native/pretty_printer.py +17 -19
- classiq/qmod/pretty_print/pretty_printer.py +9 -6
- classiq/qmod/python_classical_type.py +1 -5
- classiq/qmod/qmod_variable.py +2 -5
- classiq/qmod/quantum_expandable.py +20 -5
- classiq/qmod/quantum_function.py +23 -10
- classiq/qmod/semantics/static_semantics_visitor.py +34 -16
- classiq/qmod/semantics/validation/func_call_validation.py +9 -5
- classiq/qmod/semantics/validation/function_name_collisions_validation.py +23 -0
- classiq/qmod/symbolic.py +47 -47
- {classiq-0.60.1.dist-info → classiq-0.62.0.dist-info}/METADATA +2 -1
- {classiq-0.60.1.dist-info → classiq-0.62.0.dist-info}/RECORD +107 -103
- classiq/execution/qaoa.py +0 -86
- {classiq-0.60.1.dist-info → classiq-0.62.0.dist-info}/WHEEL +0 -0
@@ -9,6 +9,7 @@ from typing import (
|
|
9
9
|
import pydantic
|
10
10
|
from pydantic import SerializeAsAny
|
11
11
|
from pydantic_core.core_schema import ValidationInfo
|
12
|
+
from typing_extensions import Self
|
12
13
|
|
13
14
|
from classiq.interface.exceptions import ClassiqInternalError
|
14
15
|
from classiq.interface.generator.arith.register_user_input import RegisterUserInput
|
@@ -171,6 +172,12 @@ class AnonQuantumOperandDeclaration(AnonQuantumFunctionDeclaration):
|
|
171
172
|
new_instance_data["kind"] = "QuantumOperandDeclaration"
|
172
173
|
return QuantumOperandDeclaration(**new_instance_data)
|
173
174
|
|
175
|
+
@property
|
176
|
+
def element_declaration(self) -> Self:
|
177
|
+
if not self.is_list:
|
178
|
+
raise ClassiqInternalError
|
179
|
+
return self.model_copy(update={"is_list": False})
|
180
|
+
|
174
181
|
|
175
182
|
AnonQuantumFunctionDeclaration.model_rebuild()
|
176
183
|
|
@@ -4,6 +4,7 @@ import pydantic
|
|
4
4
|
|
5
5
|
from classiq.interface.ast_node import ASTNode
|
6
6
|
from classiq.interface.exceptions import ClassiqError
|
7
|
+
from classiq.interface.generator.expressions.expression import Expression
|
7
8
|
from classiq.interface.model.quantum_function_declaration import (
|
8
9
|
AnonQuantumOperandDeclaration,
|
9
10
|
)
|
@@ -52,5 +53,13 @@ class QuantumLambdaFunction(ASTNode):
|
|
52
53
|
self._func_decl = fd
|
53
54
|
|
54
55
|
|
55
|
-
|
56
|
+
class OperandIdentifier(ASTNode):
|
57
|
+
name: str
|
58
|
+
index: Expression
|
59
|
+
|
60
|
+
def __str__(self) -> str:
|
61
|
+
return f"{self.name}[{self.index.expr}]"
|
62
|
+
|
63
|
+
|
64
|
+
QuantumCallable = Union[str, OperandIdentifier, QuantumLambdaFunction]
|
56
65
|
QuantumOperand = Union[QuantumCallable, list[QuantumCallable]]
|
@@ -159,7 +159,9 @@ class QuantumNumeric(QuantumScalar):
|
|
159
159
|
def _validate_fields(self) -> Self:
|
160
160
|
has_sign = self.is_signed is not None
|
161
161
|
has_fraction_digits = self.fraction_digits is not None
|
162
|
-
if has_sign and not has_fraction_digits or
|
162
|
+
if (has_sign and not has_fraction_digits) or (
|
163
|
+
not has_sign and has_fraction_digits
|
164
|
+
):
|
163
165
|
raise ClassiqValueError(
|
164
166
|
"Assign neither or both of is_signed and fraction_digits"
|
165
167
|
)
|
@@ -61,7 +61,7 @@ def qmod_val_to_python(val: ExpressionValue, qmod_type: ClassicalType) -> Any:
|
|
61
61
|
for field_name, field_type in val.struct_declaration.variables.items()
|
62
62
|
}
|
63
63
|
|
64
|
-
if isinstance(val, Enum):
|
64
|
+
if isinstance(val, (Enum, int)):
|
65
65
|
return val
|
66
66
|
|
67
67
|
elif isinstance(qmod_type, ClassicalList):
|
@@ -147,6 +147,8 @@ def get_field(
|
|
147
147
|
proxy: Union[QmodSizedProxy, QmodStructInstance, QmodQStructProxy, list],
|
148
148
|
field: str,
|
149
149
|
) -> ExpressionValue:
|
150
|
+
if isinstance(proxy, type) and issubclass(proxy, Enum):
|
151
|
+
return getattr(proxy, field)
|
150
152
|
if isinstance(proxy, Symbol) and not isinstance(proxy, QmodSizedProxy):
|
151
153
|
raise ClassiqExpansionError(
|
152
154
|
f"Cannot evaluate '{proxy}.{field}': Variable {str(proxy)!r} is not "
|
@@ -1,8 +1,7 @@
|
|
1
1
|
import dataclasses
|
2
|
-
from collections.abc import
|
3
|
-
from contextlib import contextmanager
|
2
|
+
from collections.abc import Sequence
|
4
3
|
from dataclasses import dataclass, field
|
5
|
-
from typing import TYPE_CHECKING
|
4
|
+
from typing import TYPE_CHECKING, Optional
|
6
5
|
|
7
6
|
from classiq.interface.enum_utils import StrEnum
|
8
7
|
from classiq.interface.exceptions import (
|
@@ -16,12 +15,14 @@ from classiq.interface.model.handle_binding import HandleBinding, NestedHandleBi
|
|
16
15
|
from classiq.interface.model.port_declaration import PortDeclaration
|
17
16
|
from classiq.interface.model.quantum_function_call import ArgValue
|
18
17
|
from classiq.interface.model.quantum_type import QuantumType
|
18
|
+
from classiq.interface.model.variable_declaration_statement import (
|
19
|
+
VariableDeclarationStatement,
|
20
|
+
)
|
19
21
|
|
20
22
|
from classiq.model_expansions.capturing.mangling_utils import (
|
21
23
|
demangle_handle,
|
22
24
|
mangle_captured_var_name,
|
23
25
|
)
|
24
|
-
from classiq.model_expansions.scope import QuantumSymbol
|
25
26
|
from classiq.model_expansions.transformers.var_splitter import SymbolPart, SymbolParts
|
26
27
|
|
27
28
|
if TYPE_CHECKING:
|
@@ -71,7 +72,11 @@ class _CapturedHandle:
|
|
71
72
|
|
72
73
|
@property
|
73
74
|
def mangled_name(self) -> str:
|
74
|
-
return mangle_captured_var_name(
|
75
|
+
return mangle_captured_var_name(
|
76
|
+
self.handle.identifier,
|
77
|
+
self.defining_function.name,
|
78
|
+
self.defining_function.depth,
|
79
|
+
)
|
75
80
|
|
76
81
|
@property
|
77
82
|
def port(self) -> PortDeclaration:
|
@@ -211,7 +216,16 @@ class CapturedVars:
|
|
211
216
|
]
|
212
217
|
)
|
213
218
|
|
214
|
-
def
|
219
|
+
def filter_vars(
|
220
|
+
self,
|
221
|
+
current_function: "FunctionClosure",
|
222
|
+
current_declarations: Optional[list[VariableDeclarationStatement]] = None,
|
223
|
+
) -> "CapturedVars":
|
224
|
+
current_declared_vars = (
|
225
|
+
None
|
226
|
+
if current_declarations is None
|
227
|
+
else {decl.name for decl in current_declarations}
|
228
|
+
)
|
215
229
|
return CapturedVars(
|
216
230
|
_captured_handles=[
|
217
231
|
captured_handle
|
@@ -219,6 +233,10 @@ class CapturedVars:
|
|
219
233
|
if not _same_closure(
|
220
234
|
captured_handle.defining_function, current_function
|
221
235
|
)
|
236
|
+
or (
|
237
|
+
current_declared_vars is not None
|
238
|
+
and captured_handle.handle.name not in current_declared_vars
|
239
|
+
)
|
222
240
|
]
|
223
241
|
)
|
224
242
|
|
@@ -247,10 +265,7 @@ class CapturedVars:
|
|
247
265
|
|
248
266
|
def get_captured_mapping(self) -> SymbolParts:
|
249
267
|
return {
|
250
|
-
|
251
|
-
handle=captured_handle.handle,
|
252
|
-
quantum_type=captured_handle.quantum_type,
|
253
|
-
): [
|
268
|
+
captured_handle.handle: [
|
254
269
|
SymbolPart(
|
255
270
|
source_handle=captured_handle.handle,
|
256
271
|
target_var_name=captured_handle.mangled_name,
|
@@ -261,11 +276,8 @@ class CapturedVars:
|
|
261
276
|
if not captured_handle.is_propagated
|
262
277
|
}
|
263
278
|
|
264
|
-
|
265
|
-
|
266
|
-
previous = self._captured_handles
|
267
|
-
yield
|
268
|
-
self._captured_handles = previous
|
279
|
+
def clone(self) -> "CapturedVars":
|
280
|
+
return CapturedVars(_captured_handles=list(self._captured_handles))
|
269
281
|
|
270
282
|
|
271
283
|
def _same_closure(closure_1: "FunctionClosure", closure_2: "FunctionClosure") -> bool:
|
@@ -295,7 +307,9 @@ def validate_args_are_not_propagated(
|
|
295
307
|
)
|
296
308
|
|
297
309
|
|
298
|
-
def validate_captured_directions(
|
310
|
+
def validate_captured_directions(
|
311
|
+
captured_vars: CapturedVars, report_outin: bool = True
|
312
|
+
) -> None:
|
299
313
|
captured_inputs = [
|
300
314
|
captured_handle.handle.name
|
301
315
|
for captured_handle in captured_vars._captured_handles
|
@@ -304,7 +318,12 @@ def validate_captured_directions(captured_vars: CapturedVars) -> None:
|
|
304
318
|
captured_outputs = [
|
305
319
|
captured_handle.handle.name
|
306
320
|
for captured_handle in captured_vars._captured_handles
|
307
|
-
if captured_handle.direction
|
321
|
+
if captured_handle.direction
|
322
|
+
in (
|
323
|
+
(PortDirection.Output, PortDirection.Outin)
|
324
|
+
if report_outin
|
325
|
+
else (PortDirection.Output,)
|
326
|
+
)
|
308
327
|
]
|
309
328
|
if len(captured_inputs) > 0:
|
310
329
|
raise ClassiqExpansionError(
|
@@ -1,12 +1,9 @@
|
|
1
1
|
import re
|
2
|
-
from typing import
|
2
|
+
from typing import Optional
|
3
3
|
|
4
4
|
from classiq.interface.generator.compiler_keywords import CAPTURE_SUFFIX
|
5
5
|
from classiq.interface.model.handle_binding import HANDLE_ID_SEPARATOR, HandleBinding
|
6
6
|
|
7
|
-
if TYPE_CHECKING:
|
8
|
-
from classiq.model_expansions.closure import FunctionClosure
|
9
|
-
|
10
7
|
IDENTIFIER_PATTERN = r"[a-zA-Z_][a-zA-Z0-9_]*"
|
11
8
|
CAPTURE_PATTERN = re.compile(
|
12
9
|
rf"({IDENTIFIER_PATTERN}){CAPTURE_SUFFIX}{IDENTIFIER_PATTERN}__\d*"
|
@@ -15,24 +12,34 @@ ARRAY_CAST_SUFFIX = HANDLE_ID_SEPARATOR + "array_cast"
|
|
15
12
|
|
16
13
|
|
17
14
|
def mangle_captured_var_name(
|
18
|
-
var_name: str,
|
15
|
+
var_name: str, function_name: str, function_depth: int
|
19
16
|
) -> str:
|
20
|
-
return
|
21
|
-
f"{var_name}{CAPTURE_SUFFIX}{defining_function.name}__{defining_function.depth}"
|
22
|
-
)
|
17
|
+
return f"{var_name}{CAPTURE_SUFFIX}{function_name}__{function_depth}"
|
23
18
|
|
24
19
|
|
25
|
-
def
|
26
|
-
|
20
|
+
def _match_capture_pattern(name: str) -> Optional[re.Match[str]]:
|
21
|
+
return re.match(CAPTURE_PATTERN, name)
|
22
|
+
|
23
|
+
|
24
|
+
def is_captured_var_name(name: str) -> bool:
|
25
|
+
return _match_capture_pattern(name) is not None
|
26
|
+
|
27
|
+
|
28
|
+
def demangle_capture_name(name: str) -> str:
|
29
|
+
match = _match_capture_pattern(name)
|
27
30
|
return match.group(1) if match else name
|
28
31
|
|
29
32
|
|
30
33
|
def demangle_handle(handle: HandleBinding) -> HandleBinding:
|
31
|
-
|
34
|
+
demangled_name = demangle_name(handle.name)
|
35
|
+
return handle.rename(demangled_name)
|
36
|
+
|
37
|
+
|
38
|
+
def demangle_name(name: str) -> str:
|
32
39
|
if HANDLE_ID_SEPARATOR not in name:
|
33
|
-
return
|
40
|
+
return name
|
34
41
|
if ARRAY_CAST_SUFFIX in name:
|
35
|
-
return
|
42
|
+
return name.split(ARRAY_CAST_SUFFIX)[0]
|
36
43
|
name = re.sub(r"([^_])_\d+$", r"\1", name)
|
37
44
|
name_parts = name.split(HANDLE_ID_SEPARATOR)
|
38
45
|
new_name_parts = [name_parts[0]]
|
@@ -44,5 +51,6 @@ def demangle_handle(handle: HandleBinding) -> HandleBinding:
|
|
44
51
|
new_name_parts.append(f"[{part_left}:{part_right}]")
|
45
52
|
else:
|
46
53
|
new_name_parts.append(f".{part}")
|
47
|
-
new_name_parts = list(map(
|
48
|
-
|
54
|
+
new_name_parts = list(map(demangle_capture_name, new_name_parts))
|
55
|
+
new_name = "".join(new_name_parts)
|
56
|
+
return new_name
|
@@ -1,8 +1,7 @@
|
|
1
1
|
import dataclasses
|
2
2
|
import json
|
3
3
|
import uuid
|
4
|
-
from collections.abc import Collection,
|
5
|
-
from contextlib import contextmanager
|
4
|
+
from collections.abc import Collection, Sequence
|
6
5
|
from dataclasses import dataclass, field
|
7
6
|
from functools import singledispatch
|
8
7
|
from symtable import Symbol
|
@@ -51,11 +50,6 @@ class Closure:
|
|
51
50
|
if isinstance(param, PortDeclaration)
|
52
51
|
}
|
53
52
|
|
54
|
-
@contextmanager
|
55
|
-
def freeze(self) -> Iterator[None]:
|
56
|
-
with self.scope.freeze(), self.captured_vars.freeze():
|
57
|
-
yield
|
58
|
-
|
59
53
|
|
60
54
|
@dataclass(frozen=True)
|
61
55
|
class GenerativeClosure(Closure):
|
@@ -142,9 +136,12 @@ class FunctionClosure(Closure):
|
|
142
136
|
def set_depth(self, depth: int) -> Self:
|
143
137
|
return dataclasses.replace(self, _depth=depth)
|
144
138
|
|
145
|
-
def
|
139
|
+
def clone(self) -> Self:
|
146
140
|
return dataclasses.replace(
|
147
|
-
self,
|
141
|
+
self,
|
142
|
+
scope=self.scope.clone(),
|
143
|
+
signature_scope=self.signature_scope.clone(),
|
144
|
+
captured_vars=self.captured_vars.clone(),
|
148
145
|
)
|
149
146
|
|
150
147
|
|
@@ -135,13 +135,13 @@ def _check_classical_type_match(
|
|
135
135
|
arg_struct_name = None if not arg_is_struct else argument.struct_declaration.name
|
136
136
|
if (
|
137
137
|
arg_is_qvar
|
138
|
-
or arg_is_builtin
|
139
|
-
and (type_is_struct or
|
140
|
-
or
|
141
|
-
|
142
|
-
|
143
|
-
|
144
|
-
|
138
|
+
or (arg_is_builtin and (type_is_struct or type_is_enum))
|
139
|
+
or (arg_is_struct and (not type_is_struct or arg_struct_name != type_name))
|
140
|
+
or (
|
141
|
+
arg_is_enum
|
142
|
+
and get_qmod_type(classical_type) != CInt
|
143
|
+
and (not type_is_enum or type(argument).__name__ != type_name)
|
144
|
+
)
|
145
145
|
):
|
146
146
|
raise ClassiqExpansionError(error_message)
|
147
147
|
|
@@ -1,4 +1,5 @@
|
|
1
1
|
import ast
|
2
|
+
import re
|
2
3
|
from collections.abc import Mapping
|
3
4
|
from enum import EnumMeta
|
4
5
|
from typing import Any, Optional
|
@@ -12,7 +13,7 @@ from classiq.interface.generator.expressions.evaluated_expression import (
|
|
12
13
|
)
|
13
14
|
from classiq.interface.generator.expressions.expression import Expression
|
14
15
|
from classiq.interface.generator.expressions.expression_constants import (
|
15
|
-
|
16
|
+
CPARAM_EXECUTION_SUFFIX_PATTERN,
|
16
17
|
)
|
17
18
|
from classiq.interface.generator.expressions.expression_types import ExpressionValue
|
18
19
|
from classiq.interface.generator.expressions.sympy_supported_expressions import (
|
@@ -99,7 +100,9 @@ def _validate_undefined_vars(
|
|
99
100
|
|
100
101
|
# Ignore expanded execution parameters
|
101
102
|
undefined_vars = {
|
102
|
-
var
|
103
|
+
var
|
104
|
+
for var in undefined_vars
|
105
|
+
if not re.search(CPARAM_EXECUTION_SUFFIX_PATTERN, var)
|
103
106
|
}
|
104
107
|
|
105
108
|
if len(undefined_vars) == 1:
|
@@ -20,6 +20,9 @@ from classiq.interface.model.quantum_function_declaration import (
|
|
20
20
|
PositionalArg,
|
21
21
|
)
|
22
22
|
from classiq.interface.model.quantum_statement import QuantumStatement
|
23
|
+
from classiq.interface.model.variable_declaration_statement import (
|
24
|
+
VariableDeclarationStatement,
|
25
|
+
)
|
23
26
|
from classiq.interface.source_reference import SourceReference
|
24
27
|
|
25
28
|
from classiq.model_expansions.capturing.captured_vars import (
|
@@ -37,6 +40,14 @@ class Block:
|
|
37
40
|
statements: list[QuantumStatement] = field(default_factory=list)
|
38
41
|
captured_vars: CapturedVars = field(default_factory=CapturedVars)
|
39
42
|
|
43
|
+
@property
|
44
|
+
def variable_declarations(self) -> list[VariableDeclarationStatement]:
|
45
|
+
return [
|
46
|
+
stmt
|
47
|
+
for stmt in self.statements
|
48
|
+
if isinstance(stmt, VariableDeclarationStatement)
|
49
|
+
]
|
50
|
+
|
40
51
|
|
41
52
|
@dataclass
|
42
53
|
class OperationContext(Generic[ClosureType]):
|
@@ -81,6 +92,10 @@ class OperationBuilder:
|
|
81
92
|
def current_operation(self) -> Closure:
|
82
93
|
return self._operations[-1].closure
|
83
94
|
|
95
|
+
@property
|
96
|
+
def current_scope(self) -> Scope:
|
97
|
+
return self.current_operation.scope
|
98
|
+
|
84
99
|
@property
|
85
100
|
def current_function(self) -> FunctionClosure:
|
86
101
|
return self._get_last_function(self._operations)
|
@@ -123,9 +138,14 @@ class OperationBuilder:
|
|
123
138
|
not isinstance(self.current_operation, FunctionClosure)
|
124
139
|
and self.current_operation.name != WITHIN_APPLY_NAME
|
125
140
|
):
|
126
|
-
validate_captured_directions(
|
141
|
+
validate_captured_directions(
|
142
|
+
captured_vars.filter_vars(
|
143
|
+
self.current_function, self.current_block.variable_declarations
|
144
|
+
),
|
145
|
+
report_outin=False,
|
146
|
+
)
|
127
147
|
self.current_operation.captured_vars.update(
|
128
|
-
captured_vars.
|
148
|
+
captured_vars.filter_vars(self.current_function)
|
129
149
|
)
|
130
150
|
self._blocks.pop()
|
131
151
|
|
@@ -149,7 +169,7 @@ class OperationBuilder:
|
|
149
169
|
return
|
150
170
|
within_captured_vars = self._operations[-1].blocks["within"].captured_vars
|
151
171
|
self.current_operation.captured_vars.update(
|
152
|
-
within_captured_vars.
|
172
|
+
within_captured_vars.filter_vars(self.current_function).negate()
|
153
173
|
)
|
154
174
|
|
155
175
|
def _propagate_captured_vars(self) -> None:
|
@@ -160,7 +180,9 @@ class OperationBuilder:
|
|
160
180
|
if len(self._operations) < 2:
|
161
181
|
return
|
162
182
|
parent_block = self._operations[-2].blocks[self._blocks[-1]]
|
163
|
-
parent_block.captured_vars.update(
|
183
|
+
parent_block.captured_vars.update(
|
184
|
+
captured_vars.filter_vars(self.parent_function)
|
185
|
+
)
|
164
186
|
|
165
187
|
@contextmanager
|
166
188
|
def source_ref_context(
|
@@ -1,31 +1,23 @@
|
|
1
1
|
from collections.abc import Mapping
|
2
2
|
from typing import TYPE_CHECKING, Any
|
3
3
|
|
4
|
-
from classiq.interface.exceptions import ClassiqInternalExpansionError
|
5
4
|
from classiq.interface.generator.expressions.qmod_struct_instance import (
|
6
5
|
QmodStructInstance,
|
7
6
|
)
|
8
7
|
from classiq.interface.generator.functions.type_name import Struct
|
9
|
-
from classiq.interface.generator.visitor import Visitor
|
10
8
|
from classiq.interface.helpers.pydantic_model_helpers import nameables_to_dict
|
11
9
|
from classiq.interface.model.native_function_definition import NativeFunctionDefinition
|
12
10
|
from classiq.interface.model.port_declaration import PortDeclaration
|
13
|
-
from classiq.interface.model.quantum_function_call import ArgValue, QuantumFunctionCall
|
14
11
|
from classiq.interface.model.quantum_function_declaration import (
|
15
12
|
PositionalArg,
|
16
13
|
QuantumFunctionDeclaration,
|
17
14
|
QuantumOperandDeclaration,
|
18
15
|
)
|
19
|
-
from classiq.interface.model.quantum_lambda_function import (
|
20
|
-
QuantumCallable,
|
21
|
-
QuantumLambdaFunction,
|
22
|
-
)
|
23
16
|
from classiq.interface.model.quantum_statement import QuantumStatement
|
24
17
|
|
25
18
|
from classiq.model_expansions.closure import (
|
26
19
|
FunctionClosure,
|
27
20
|
GenerativeClosure,
|
28
|
-
GenerativeFunctionClosure,
|
29
21
|
)
|
30
22
|
from classiq.model_expansions.scope import Evaluated, QuantumSymbol
|
31
23
|
from classiq.qmod.generative import generative_mode_context, set_frontend_interpreter
|
@@ -35,7 +27,6 @@ from classiq.qmod.qmod_variable import QNum, _create_qvar_for_qtype
|
|
35
27
|
from classiq.qmod.quantum_callable import QCallable
|
36
28
|
from classiq.qmod.quantum_expandable import (
|
37
29
|
QExpandable,
|
38
|
-
QLambdaFunction,
|
39
30
|
QTerminalCallable,
|
40
31
|
)
|
41
32
|
from classiq.qmod.quantum_function import QFunc
|
@@ -71,12 +62,18 @@ def translate_ast_arg_to_python_qmod(param: PositionalArg, evaluated: Evaluated)
|
|
71
62
|
)
|
72
63
|
if isinstance(param, QuantumOperandDeclaration):
|
73
64
|
if param.is_list:
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
65
|
+
func_list: list[FunctionClosure] = evaluated.as_type(list)
|
66
|
+
return LenList(
|
67
|
+
[
|
68
|
+
QTerminalCallable(
|
69
|
+
QuantumOperandDeclaration(
|
70
|
+
name=param.name,
|
71
|
+
positional_arg_declarations=param.positional_arg_declarations,
|
72
|
+
),
|
73
|
+
index_=idx,
|
74
|
+
)
|
75
|
+
for idx in range(len(func_list))
|
76
|
+
]
|
80
77
|
)
|
81
78
|
else:
|
82
79
|
func = evaluated.as_type(FunctionClosure)
|
@@ -119,7 +116,7 @@ class _InterpreterExpandable(QFunc):
|
|
119
116
|
name=name,
|
120
117
|
positional_arg_declarations=evaluated.value.positional_arg_declarations,
|
121
118
|
)
|
122
|
-
for name, evaluated in self._interpreter.
|
119
|
+
for name, evaluated in self._interpreter._builder.current_scope.items()
|
123
120
|
if isinstance(evaluated, Evaluated)
|
124
121
|
and isinstance(evaluated.value, FunctionClosure)
|
125
122
|
} | nameables_to_dict(self._interpreter._get_function_declarations())
|
@@ -143,78 +140,3 @@ def emit_generative_statements(
|
|
143
140
|
True
|
144
141
|
):
|
145
142
|
generative_function._py_callable(*python_qmod_args)
|
146
|
-
|
147
|
-
|
148
|
-
def emit_operands_as_declarative(
|
149
|
-
interpreter: "Interpreter", param: PositionalArg, arg: Evaluated
|
150
|
-
) -> ArgValue:
|
151
|
-
if not isinstance(param, QuantumOperandDeclaration):
|
152
|
-
return arg.emit()
|
153
|
-
value = arg.value
|
154
|
-
if isinstance(value, list):
|
155
|
-
return [
|
156
|
-
_expand_operand_as_declarative(interpreter, param, item) for item in value
|
157
|
-
]
|
158
|
-
if isinstance(value, GenerativeFunctionClosure):
|
159
|
-
return _expand_operand_as_declarative(interpreter, param, value)
|
160
|
-
if isinstance(value, FunctionClosure):
|
161
|
-
if value.is_lambda:
|
162
|
-
raise ClassiqInternalExpansionError
|
163
|
-
_register_declarative_function(interpreter, value.name)
|
164
|
-
return value.name
|
165
|
-
raise ClassiqInternalExpansionError
|
166
|
-
|
167
|
-
|
168
|
-
def _expand_operand_as_declarative(
|
169
|
-
interpreter: "Interpreter",
|
170
|
-
param: QuantumOperandDeclaration,
|
171
|
-
arg: GenerativeFunctionClosure,
|
172
|
-
) -> QuantumCallable:
|
173
|
-
if not arg.is_lambda:
|
174
|
-
_register_declarative_function(interpreter, arg.name)
|
175
|
-
return arg.name
|
176
|
-
val = QLambdaFunction(param, arg.generative_blocks["body"]._py_callable)
|
177
|
-
with generative_mode_context(False):
|
178
|
-
val.expand()
|
179
|
-
_DecFuncVisitor(interpreter).visit(val.body)
|
180
|
-
qlambda = QuantumLambdaFunction(
|
181
|
-
pos_rename_params=val.infer_rename_params(),
|
182
|
-
body=val.body,
|
183
|
-
)
|
184
|
-
qlambda.set_op_decl(param)
|
185
|
-
return qlambda
|
186
|
-
|
187
|
-
|
188
|
-
def _register_declarative_function(interpreter: "Interpreter", func_name: str) -> None:
|
189
|
-
if func_name in nameables_to_dict(list(interpreter._expanded_functions.values())):
|
190
|
-
return
|
191
|
-
|
192
|
-
for user_gen_func in interpreter._generative_functions:
|
193
|
-
if user_gen_func.func_decl.name == func_name:
|
194
|
-
break
|
195
|
-
else:
|
196
|
-
return
|
197
|
-
|
198
|
-
with generative_mode_context(False):
|
199
|
-
dec_func = QFunc(user_gen_func._py_callable)
|
200
|
-
dec_func.expand()
|
201
|
-
dec_func_def = QMODULE.native_defs[func_name]
|
202
|
-
interpreter._expanded_functions[func_name] = dec_func_def
|
203
|
-
_DecFuncVisitor(interpreter).visit(dec_func_def)
|
204
|
-
|
205
|
-
|
206
|
-
class _DecFuncVisitor(Visitor):
|
207
|
-
def __init__(self, interpreter: "Interpreter"):
|
208
|
-
self._interpreter = interpreter
|
209
|
-
|
210
|
-
def visit_QuantumFunctionCall(self, call: QuantumFunctionCall) -> None:
|
211
|
-
_register_declarative_function(self._interpreter, call.func_name)
|
212
|
-
for arg in call.positional_args:
|
213
|
-
if isinstance(arg, str):
|
214
|
-
arg = [arg]
|
215
|
-
if isinstance(arg, list):
|
216
|
-
for possible_func_name in arg:
|
217
|
-
if isinstance(possible_func_name, str):
|
218
|
-
_register_declarative_function(
|
219
|
-
self._interpreter, possible_func_name
|
220
|
-
)
|