classiq 0.58.1__py3-none-any.whl → 0.60.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/_internals/api_wrapper.py +91 -20
- classiq/_internals/client.py +48 -11
- classiq/_internals/jobs.py +47 -40
- classiq/execution/execution_session.py +62 -22
- classiq/execution/jobs.py +64 -23
- classiq/execution/qaoa.py +17 -15
- classiq/execution/qnn.py +17 -18
- classiq/executor.py +2 -1
- classiq/interface/_version.py +1 -1
- classiq/interface/generator/arith/arithmetic_operations.py +1 -0
- classiq/interface/generator/register_role.py +8 -0
- classiq/interface/model/handle_binding.py +22 -3
- classiq/model_expansions/capturing/captured_vars.py +316 -0
- classiq/model_expansions/capturing/mangling_utils.py +18 -9
- classiq/model_expansions/closure.py +29 -74
- classiq/model_expansions/function_builder.py +51 -66
- classiq/model_expansions/interpreter.py +4 -7
- classiq/model_expansions/quantum_operations/bind.py +1 -3
- classiq/model_expansions/quantum_operations/call_emitter.py +46 -11
- classiq/model_expansions/quantum_operations/classicalif.py +2 -5
- classiq/model_expansions/quantum_operations/control.py +13 -16
- classiq/model_expansions/quantum_operations/emitter.py +36 -8
- classiq/model_expansions/quantum_operations/expression_operation.py +9 -19
- classiq/model_expansions/quantum_operations/inplace_binary_operation.py +4 -6
- classiq/model_expansions/quantum_operations/invert.py +5 -8
- classiq/model_expansions/quantum_operations/power.py +5 -10
- classiq/model_expansions/quantum_operations/quantum_assignment_operation.py +1 -3
- classiq/model_expansions/quantum_operations/quantum_function_call.py +1 -3
- classiq/model_expansions/quantum_operations/repeat.py +3 -3
- classiq/model_expansions/quantum_operations/variable_decleration.py +1 -1
- classiq/model_expansions/quantum_operations/within_apply.py +1 -5
- classiq/model_expansions/scope.py +2 -2
- classiq/model_expansions/transformers/var_splitter.py +32 -19
- classiq/model_expansions/utils/handles_collector.py +33 -0
- classiq/model_expansions/visitors/variable_references.py +18 -2
- classiq/qmod/qfunc.py +9 -13
- classiq/qmod/quantum_expandable.py +1 -21
- classiq/qmod/quantum_function.py +16 -0
- {classiq-0.58.1.dist-info → classiq-0.60.0.dist-info}/METADATA +1 -1
- {classiq-0.58.1.dist-info → classiq-0.60.0.dist-info}/RECORD +41 -42
- classiq/interface/executor/aws_execution_cost.py +0 -90
- classiq/model_expansions/capturing/captured_var_manager.py +0 -48
- classiq/model_expansions/capturing/propagated_var_stack.py +0 -194
- {classiq-0.58.1.dist-info → classiq-0.60.0.dist-info}/WHEEL +0 -0
@@ -10,15 +10,12 @@ from classiq.model_expansions.scope import Scope
|
|
10
10
|
|
11
11
|
class InvertEmitter(CallEmitter[Invert]):
|
12
12
|
def emit(self, invert: Invert, /) -> None:
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
def _emit_propagated(self, invert: Invert, /) -> None:
|
17
|
-
if invert.is_generative():
|
13
|
+
is_generative = invert.is_generative()
|
14
|
+
if is_generative:
|
18
15
|
context = self._register_generative_context(invert, INVERT_OPERATOR_NAME)
|
19
16
|
invert = invert.model_copy(update={"body": context.statements("body")})
|
20
17
|
|
21
|
-
if self._should_wrap(invert.body):
|
18
|
+
if not is_generative and self._should_wrap(invert.body):
|
22
19
|
self._emit_wrapped(invert)
|
23
20
|
return
|
24
21
|
|
@@ -31,7 +28,7 @@ class InvertEmitter(CallEmitter[Invert]):
|
|
31
28
|
scope=Scope(parent=self._current_scope),
|
32
29
|
)
|
33
30
|
context = self._expand_operation(invert_operation)
|
34
|
-
self.
|
31
|
+
self.emit_statement(
|
35
32
|
Invert(body=context.statements("body"), source_ref=invert.source_ref)
|
36
33
|
)
|
37
34
|
|
@@ -39,6 +36,6 @@ class InvertEmitter(CallEmitter[Invert]):
|
|
39
36
|
wrapping_function = self._create_expanded_wrapping_function(
|
40
37
|
INVERT_OPERATOR_NAME, invert.body
|
41
38
|
)
|
42
|
-
self.
|
39
|
+
self.emit_statement(
|
43
40
|
Invert(body=[wrapping_function], source_ref=invert.source_ref)
|
44
41
|
)
|
@@ -22,10 +22,6 @@ class PowerEmitter(CallEmitter[Power]):
|
|
22
22
|
_power_expr: Expression
|
23
23
|
|
24
24
|
def emit(self, power: Power, /) -> None:
|
25
|
-
with self._propagated_var_stack.capture_variables(power):
|
26
|
-
self._emit_propagated(power)
|
27
|
-
|
28
|
-
def _emit_propagated(self, power: Power) -> None:
|
29
25
|
if power.is_generative():
|
30
26
|
context = self._register_generative_context(power, POWER_OPERATOR_NAME)
|
31
27
|
power = power.model_copy(update={"body": context.statements("body")})
|
@@ -50,7 +46,7 @@ class PowerEmitter(CallEmitter[Power]):
|
|
50
46
|
scope=Scope(parent=self._current_scope),
|
51
47
|
)
|
52
48
|
context = self._expand_operation(power_operation)
|
53
|
-
self.
|
49
|
+
self.emit_statement(
|
54
50
|
Power(
|
55
51
|
body=context.statements("body"),
|
56
52
|
power=self._power_expr,
|
@@ -59,11 +55,10 @@ class PowerEmitter(CallEmitter[Power]):
|
|
59
55
|
)
|
60
56
|
|
61
57
|
def _emit_wrapped(self) -> None:
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
self._builder.emit_statement(
|
58
|
+
wrapping_function = self._create_expanded_wrapping_function(
|
59
|
+
POWER_OPERATOR_NAME, self._power.body
|
60
|
+
)
|
61
|
+
self.emit_statement(
|
67
62
|
Power(
|
68
63
|
body=[wrapping_function],
|
69
64
|
power=self._power_expr,
|
@@ -79,8 +79,6 @@ class QuantumAssignmentOperationEmitter(
|
|
79
79
|
|
80
80
|
def _emit_op(self, expression: Expression, op: QuantumAssignmentOperation) -> None:
|
81
81
|
op = self._evaluate_types_in_expression(op, expression)
|
82
|
-
with self._propagated_var_stack.capture_variables(op):
|
83
|
-
pass # This propagates the expression variables
|
84
82
|
if isinstance(op, ArithmeticOperation):
|
85
83
|
self._emit_arithmetic_op(op, expression)
|
86
84
|
return
|
@@ -130,7 +128,7 @@ class QuantumAssignmentOperationEmitter(
|
|
130
128
|
) -> None:
|
131
129
|
result = self._interpreter.evaluate(op.result_var).as_type(QuantumSymbol)
|
132
130
|
copy_type_information(op.result_type, result.quantum_type, str(result.handle))
|
133
|
-
self.
|
131
|
+
self.emit_statement(op)
|
134
132
|
|
135
133
|
def _optimize_boolean_expression(
|
136
134
|
self, op: ArithmeticOperation, expression: Expression
|
@@ -18,7 +18,5 @@ 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(
|
22
|
-
function.name
|
23
|
-
), function.scope.freeze(), self._propagated_var_stack.capture_variables(call):
|
21
|
+
with ErrorManager().call(function.name), function.freeze():
|
24
22
|
self._emit_quantum_function_call(function, args)
|
@@ -23,10 +23,9 @@ class RepeatEmitter(CallEmitter[Repeat]):
|
|
23
23
|
f"repeat count must be non-negative, got {count}"
|
24
24
|
)
|
25
25
|
for i in range(count):
|
26
|
-
|
27
|
-
self._emit_propagated(repeat, i)
|
26
|
+
self._emit_iteration(repeat, i)
|
28
27
|
|
29
|
-
def
|
28
|
+
def _emit_iteration(self, repeat: Repeat, i: int) -> None:
|
30
29
|
closure_constructor: type[FunctionClosure]
|
31
30
|
extra_args: dict
|
32
31
|
if repeat.is_generative():
|
@@ -50,6 +49,7 @@ class RepeatEmitter(CallEmitter[Repeat]):
|
|
50
49
|
],
|
51
50
|
body=repeat.body,
|
52
51
|
scope=Scope(parent=self._current_scope),
|
52
|
+
is_lambda=True,
|
53
53
|
**extra_args,
|
54
54
|
)
|
55
55
|
self._emit_quantum_function_call(iteration_function, [Expression(expr=str(i))])
|
@@ -10,10 +10,6 @@ from classiq.model_expansions.scope import Scope
|
|
10
10
|
|
11
11
|
class WithinApplyEmitter(Emitter[WithinApply]):
|
12
12
|
def emit(self, within_apply: WithinApply, /) -> None:
|
13
|
-
with self._propagated_var_stack.capture_variables(within_apply):
|
14
|
-
self._emit_propagated(within_apply)
|
15
|
-
|
16
|
-
def _emit_propagated(self, within_apply: WithinApply) -> None:
|
17
13
|
if within_apply.is_generative():
|
18
14
|
within_apply_context = self._register_generative_context(
|
19
15
|
within_apply, WITHIN_APPLY_NAME, ["within", "apply"]
|
@@ -34,7 +30,7 @@ class WithinApplyEmitter(Emitter[WithinApply]):
|
|
34
30
|
scope=Scope(parent=self._current_scope),
|
35
31
|
)
|
36
32
|
context = self._expand_operation(within_apply_operation)
|
37
|
-
self.
|
33
|
+
self.emit_statement(
|
38
34
|
WithinApply(
|
39
35
|
compute=context.statements("within"),
|
40
36
|
action=context.statements("apply"),
|
@@ -34,7 +34,7 @@ from classiq.interface.model.quantum_type import (
|
|
34
34
|
)
|
35
35
|
|
36
36
|
if TYPE_CHECKING:
|
37
|
-
from classiq.model_expansions.closure import
|
37
|
+
from classiq.model_expansions.closure import FunctionClosure
|
38
38
|
|
39
39
|
T = TypeVar("T")
|
40
40
|
|
@@ -138,7 +138,7 @@ def _evaluated_to_str_struct_literal(value: QmodStructInstance) -> str:
|
|
138
138
|
@dataclass(frozen=True)
|
139
139
|
class Evaluated: # FIXME: Merge with EvaluatedExpression if possible
|
140
140
|
value: Any
|
141
|
-
defining_function: Optional["
|
141
|
+
defining_function: Optional["FunctionClosure"] = None
|
142
142
|
|
143
143
|
def as_type(self, t: type[T]) -> T:
|
144
144
|
if t is int:
|
@@ -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
|
4
|
+
from typing import TYPE_CHECKING, Callable, TypeVar, cast
|
5
5
|
|
6
6
|
from classiq.interface.exceptions import (
|
7
7
|
ClassiqExpansionError,
|
@@ -15,6 +15,9 @@ from classiq.interface.model.handle_binding import (
|
|
15
15
|
NestedHandleBinding,
|
16
16
|
SlicedHandleBinding,
|
17
17
|
)
|
18
|
+
from classiq.interface.model.quantum_expressions.quantum_expression import (
|
19
|
+
QuantumExpressionOperation,
|
20
|
+
)
|
18
21
|
from classiq.interface.model.quantum_type import (
|
19
22
|
QuantumBitvector,
|
20
23
|
QuantumScalar,
|
@@ -54,8 +57,9 @@ class VarSplitter:
|
|
54
57
|
vrc.visit(ast.parse(expression.expr))
|
55
58
|
symbol_names_to_split = dict.fromkeys(
|
56
59
|
handle.name
|
57
|
-
for handle in
|
58
|
-
if isinstance(handle,
|
60
|
+
for handle in vrc.var_handles
|
61
|
+
if isinstance(self._scope[handle.name].value, QuantumSymbol)
|
62
|
+
and isinstance(handle, NestedHandleBinding)
|
59
63
|
)
|
60
64
|
|
61
65
|
symbol_handles = {
|
@@ -85,13 +89,6 @@ class VarSplitter:
|
|
85
89
|
for symbol, handles in symbol_handles.items()
|
86
90
|
}
|
87
91
|
|
88
|
-
def _get_handles(self, collector: VarRefCollector) -> list[HandleBinding]:
|
89
|
-
return [
|
90
|
-
handle
|
91
|
-
for handle in collector.var_handles
|
92
|
-
if isinstance(self._scope[handle.name].value, QuantumSymbol)
|
93
|
-
]
|
94
|
-
|
95
92
|
def _get_symbol_parts(
|
96
93
|
self, symbol: QuantumSymbol, target_parts: list[HandleBinding]
|
97
94
|
) -> list[QuantumSymbol]:
|
@@ -184,14 +181,9 @@ class VarSplitter:
|
|
184
181
|
for part in chain.from_iterable(symbol_parts.values())
|
185
182
|
]
|
186
183
|
|
187
|
-
def _check_all_handles_were_replaced(self, new_expr_str: str) -> None:
|
188
|
-
vrc = VarRefCollector(ignore_duplicated_handles=True)
|
189
|
-
vrc.visit(ast.parse(new_expr_str))
|
190
|
-
for handle in self._get_handles(vrc):
|
191
|
-
if isinstance(handle, NestedHandleBinding):
|
192
|
-
raise ClassiqInternalExpansionError(f"Did not replace handle {handle}")
|
193
|
-
|
194
184
|
def rewrite(self, subject: AST_NODE, symbol_mapping: SymbolParts) -> AST_NODE:
|
185
|
+
if len(symbol_mapping) == 0:
|
186
|
+
return subject
|
195
187
|
handle_replacements = {
|
196
188
|
part.source_handle: part.target_var_handle
|
197
189
|
for parts in symbol_mapping.values()
|
@@ -210,6 +202,22 @@ class VarSplitter:
|
|
210
202
|
def visit_Expression(expr: Expression) -> Expression:
|
211
203
|
return self._rewrite_expression(symbol_mapping, expr)
|
212
204
|
|
205
|
+
def visit_QuantumExpressionOperation(
|
206
|
+
self, op: QuantumExpressionOperation
|
207
|
+
) -> QuantumExpressionOperation:
|
208
|
+
op = cast(QuantumExpressionOperation, self.generic_visit(op))
|
209
|
+
previous_var_handles = list(op._var_handles)
|
210
|
+
op._var_handles = self.visit(op._var_handles)
|
211
|
+
op._var_types = {
|
212
|
+
new_handle.name: op._var_types.get(
|
213
|
+
new_handle.name, op._var_types[previous_handle.name]
|
214
|
+
)
|
215
|
+
for previous_handle, new_handle in zip(
|
216
|
+
previous_var_handles, op._var_handles
|
217
|
+
)
|
218
|
+
}
|
219
|
+
return op
|
220
|
+
|
213
221
|
return ReplaceSplitVars().visit(subject)
|
214
222
|
|
215
223
|
def _rewrite_expression(
|
@@ -232,6 +240,11 @@ class VarSplitter:
|
|
232
240
|
new_expr_str = new_expr_str.replace(
|
233
241
|
str(handle), handle_names[collapsed_handle]
|
234
242
|
)
|
235
|
-
|
243
|
+
if handle.qmod_expr != str(handle):
|
244
|
+
new_expr_str = new_expr_str.replace(
|
245
|
+
handle.qmod_expr, handle_names[collapsed_handle]
|
246
|
+
)
|
236
247
|
|
237
|
-
|
248
|
+
new_expr = Expression(expr=new_expr_str)
|
249
|
+
new_expr._evaluated_expr = expression._evaluated_expr
|
250
|
+
return new_expr
|
@@ -0,0 +1,33 @@
|
|
1
|
+
import ast
|
2
|
+
|
3
|
+
from classiq.interface.generator.expressions.expression import Expression
|
4
|
+
from classiq.interface.generator.visitor import NodeType, Visitor
|
5
|
+
from classiq.interface.model.handle_binding import HandleBinding
|
6
|
+
from classiq.interface.model.quantum_expressions.quantum_expression import (
|
7
|
+
QuantumExpressionOperation,
|
8
|
+
)
|
9
|
+
|
10
|
+
from classiq.model_expansions.visitors.variable_references import VarRefCollector
|
11
|
+
|
12
|
+
|
13
|
+
class _HandlesCollector(Visitor):
|
14
|
+
def __init__(self) -> None:
|
15
|
+
self.handles: list[HandleBinding] = []
|
16
|
+
|
17
|
+
def visit_HandleBinding(self, handle: HandleBinding) -> None:
|
18
|
+
self.handles.append(handle)
|
19
|
+
|
20
|
+
def visit_Expression(self, expression: Expression) -> None:
|
21
|
+
vrc = VarRefCollector(ignore_duplicated_handles=True)
|
22
|
+
vrc.visit(ast.parse(expression.expr))
|
23
|
+
self.handles.extend(vrc.var_handles)
|
24
|
+
|
25
|
+
def visit_QuantumExpressionOperation(self, op: QuantumExpressionOperation) -> None:
|
26
|
+
self.handles.extend(op.var_handles)
|
27
|
+
self.generic_visit(op)
|
28
|
+
|
29
|
+
|
30
|
+
def extract_handles(node: NodeType) -> list[HandleBinding]:
|
31
|
+
collector = _HandlesCollector()
|
32
|
+
collector.visit(node)
|
33
|
+
return collector.handles
|
@@ -80,13 +80,29 @@ class VarRefCollector(ast.NodeVisitor):
|
|
80
80
|
return handle
|
81
81
|
|
82
82
|
def visit_Attribute(self, node: ast.Attribute) -> Optional[FieldHandleBinding]:
|
83
|
+
return self._get_field_handle(node.value, node.attr)
|
84
|
+
|
85
|
+
def visit_Call(self, node: ast.Call) -> Optional[FieldHandleBinding]:
|
86
|
+
if (
|
87
|
+
not isinstance(node.func, ast.Name)
|
88
|
+
or node.func.id != "get_field"
|
89
|
+
or len(node.args) != 2
|
90
|
+
or not isinstance(node.args[1], ast.Constant)
|
91
|
+
or not isinstance(node.args[1].value, str)
|
92
|
+
):
|
93
|
+
return self.generic_visit(node)
|
94
|
+
return self._get_field_handle(node.args[0], node.args[1].value)
|
95
|
+
|
96
|
+
def _get_field_handle(
|
97
|
+
self, subject: ast.expr, field: str
|
98
|
+
) -> Optional[FieldHandleBinding]:
|
83
99
|
with self.set_nested():
|
84
|
-
base_handle = self.visit(
|
100
|
+
base_handle = self.visit(subject)
|
85
101
|
if base_handle is None:
|
86
102
|
return None
|
87
103
|
handle = FieldHandleBinding(
|
88
104
|
base_handle=base_handle,
|
89
|
-
field=
|
105
|
+
field=field,
|
90
106
|
)
|
91
107
|
if not self._is_nested:
|
92
108
|
self._var_handles[handle] = True
|
classiq/qmod/qfunc.py
CHANGED
@@ -27,28 +27,24 @@ def set_discovered_functions(
|
|
27
27
|
def qfunc(func: Callable) -> QFunc: ...
|
28
28
|
|
29
29
|
|
30
|
-
@overload
|
31
|
-
def qfunc(*, synthesize_separately: Literal[True]) -> Callable[[Callable], QFunc]: ...
|
32
|
-
|
33
|
-
|
34
|
-
@overload
|
35
|
-
def qfunc(*, external: Literal[True]) -> Callable[[Callable], ExternalQFunc]: ...
|
36
|
-
|
37
|
-
|
38
30
|
@overload
|
39
31
|
def qfunc(
|
40
|
-
*,
|
32
|
+
*,
|
33
|
+
external: Literal[True],
|
34
|
+
synthesize_separately: Literal[False] = False,
|
41
35
|
) -> Callable[[Callable], ExternalQFunc]: ...
|
42
36
|
|
43
37
|
|
44
38
|
@overload
|
45
|
-
def qfunc(
|
39
|
+
def qfunc(
|
40
|
+
*,
|
41
|
+
generative: Literal[True],
|
42
|
+
synthesize_separately: bool = False,
|
43
|
+
) -> Callable[[Callable], GenerativeQFunc]: ...
|
46
44
|
|
47
45
|
|
48
46
|
@overload
|
49
|
-
def qfunc(
|
50
|
-
*, generative: Literal[True], synthesize_separately: Literal[True]
|
51
|
-
) -> Callable[[Callable], GenerativeQFunc]: ...
|
47
|
+
def qfunc(*, synthesize_separately: bool) -> Callable[[Callable], QFunc]: ...
|
52
48
|
|
53
49
|
|
54
50
|
def qfunc(
|
@@ -1,5 +1,4 @@
|
|
1
1
|
import inspect
|
2
|
-
import warnings
|
3
2
|
from abc import ABC
|
4
3
|
from dataclasses import is_dataclass
|
5
4
|
from enum import Enum as PythonEnum
|
@@ -19,7 +18,7 @@ import pydantic
|
|
19
18
|
from sympy import Basic
|
20
19
|
from typing_extensions import Self
|
21
20
|
|
22
|
-
from classiq.interface.exceptions import
|
21
|
+
from classiq.interface.exceptions import ClassiqValueError
|
23
22
|
from classiq.interface.generator.expressions.expression import Expression
|
24
23
|
from classiq.interface.generator.functions.concrete_types import (
|
25
24
|
NativePythonClassicalTypes,
|
@@ -390,7 +389,6 @@ def _get_operand_hint(
|
|
390
389
|
def _prepare_args(
|
391
390
|
decl: AnonQuantumFunctionDeclaration, arg_list: list[Any], kwargs: dict[str, Any]
|
392
391
|
) -> list[ArgValue]:
|
393
|
-
_apply_control_backward_compatibility(decl, kwargs)
|
394
392
|
result = []
|
395
393
|
for idx, arg_decl in enumerate(decl.positional_arg_declarations):
|
396
394
|
arg = None
|
@@ -413,24 +411,6 @@ def _prepare_args(
|
|
413
411
|
return result
|
414
412
|
|
415
413
|
|
416
|
-
def _apply_control_backward_compatibility(
|
417
|
-
decl: AnonQuantumFunctionDeclaration, kwargs: dict[str, Any]
|
418
|
-
) -> None:
|
419
|
-
from classiq.qmod.builtins.functions import __all__ as builtin_functions
|
420
|
-
|
421
|
-
if decl.name in builtin_functions and "control" in kwargs:
|
422
|
-
warnings.warn(
|
423
|
-
f"Parameter 'control' of function {decl.name!r} has been renamed to "
|
424
|
-
f"'ctrl'. Parameter 'control' will no longer be supported starting on "
|
425
|
-
f"4/11/24 at the earliest.\nHint: Change {decl.name}(control=...) to "
|
426
|
-
f"{decl.name}(ctrl=...).",
|
427
|
-
ClassiqDeprecationWarning,
|
428
|
-
stacklevel=6,
|
429
|
-
)
|
430
|
-
kwargs["ctrl"] = kwargs["control"]
|
431
|
-
kwargs.pop("control")
|
432
|
-
|
433
|
-
|
434
414
|
def _create_quantum_function_call(
|
435
415
|
decl_: QuantumFunctionDeclaration,
|
436
416
|
index_: Optional[Union[CParamScalar, int]] = None,
|
classiq/qmod/quantum_function.py
CHANGED
@@ -7,6 +7,9 @@ from typing import Any, Callable, Optional, get_origin
|
|
7
7
|
|
8
8
|
from classiq.interface.exceptions import ClassiqError
|
9
9
|
from classiq.interface.executor.execution_preferences import ExecutionPreferences
|
10
|
+
from classiq.interface.generator.functions.port_declaration import (
|
11
|
+
PortDeclarationDirection,
|
12
|
+
)
|
10
13
|
from classiq.interface.generator.model.constraints import Constraints
|
11
14
|
from classiq.interface.generator.model.preferences.preferences import Preferences
|
12
15
|
from classiq.interface.generator.types.compilation_metadata import CompilationMetadata
|
@@ -37,7 +40,20 @@ class BaseQFunc(QExpandable):
|
|
37
40
|
super().__init__(py_callable)
|
38
41
|
self.compilation_metadata = compilation_metadata
|
39
42
|
|
43
|
+
@property
|
44
|
+
def func_decl(self) -> NamedParamsQuantumFunctionDeclaration:
|
45
|
+
raise NotImplementedError
|
46
|
+
|
47
|
+
@property
|
48
|
+
def _has_inputs(self) -> bool:
|
49
|
+
return any(
|
50
|
+
port.direction == PortDeclarationDirection.Input
|
51
|
+
for port in self.func_decl.port_declarations
|
52
|
+
)
|
53
|
+
|
40
54
|
def update_compilation_metadata(self, **kwargs: Any) -> None:
|
55
|
+
if kwargs["should_synthesize_separately"] and self._has_inputs:
|
56
|
+
raise ClassiqError("Can't synthesize separately a function with inputs")
|
41
57
|
self.compilation_metadata = self._compilation_metadata.model_copy(update=kwargs)
|
42
58
|
|
43
59
|
@property
|