classiq 0.39.0__py3-none-any.whl → 0.41.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 +5 -2
- classiq/_internals/api_wrapper.py +3 -21
- classiq/applications/chemistry/chemistry_model_constructor.py +87 -101
- classiq/applications/combinatorial_helpers/combinatorial_problem_utils.py +7 -26
- classiq/applications/combinatorial_helpers/optimization_model.py +7 -6
- classiq/applications/combinatorial_helpers/pauli_helpers/pauli_utils.py +33 -55
- classiq/applications/combinatorial_optimization/__init__.py +4 -0
- classiq/applications/combinatorial_optimization/combinatorial_optimization_model_constructor.py +29 -26
- classiq/applications/finance/finance_model_constructor.py +23 -26
- classiq/applications/grover/grover_model_constructor.py +37 -38
- classiq/applications/qsvm/qsvm.py +1 -2
- classiq/applications/qsvm/qsvm_model_constructor.py +15 -16
- classiq/execution/__init__.py +4 -0
- classiq/execution/execution_session.py +151 -0
- classiq/execution/qnn.py +80 -0
- classiq/executor.py +2 -109
- classiq/interface/_version.py +1 -1
- classiq/interface/analyzer/analysis_params.py +11 -0
- classiq/interface/applications/qsvm.py +0 -8
- classiq/interface/ast_node.py +12 -2
- classiq/interface/backend/backend_preferences.py +30 -6
- classiq/interface/backend/quantum_backend_providers.py +11 -11
- classiq/interface/executor/execution_preferences.py +7 -67
- classiq/interface/executor/execution_result.py +22 -1
- classiq/interface/generator/application_apis/chemistry_declarations.py +2 -4
- classiq/interface/generator/application_apis/finance_declarations.py +1 -1
- classiq/interface/generator/arith/binary_ops.py +88 -25
- classiq/interface/generator/arith/unary_ops.py +28 -19
- classiq/interface/generator/expressions/atomic_expression_functions.py +6 -2
- classiq/interface/generator/expressions/enums/__init__.py +10 -0
- classiq/interface/generator/expressions/enums/classical_enum.py +5 -1
- classiq/interface/generator/expressions/expression.py +9 -2
- classiq/interface/generator/expressions/qmod_qarray_proxy.py +89 -0
- classiq/interface/generator/expressions/qmod_qscalar_proxy.py +20 -0
- classiq/interface/generator/expressions/qmod_sized_proxy.py +22 -0
- classiq/interface/generator/expressions/sympy_supported_expressions.py +10 -1
- classiq/interface/generator/functions/builtins/core_library/atomic_quantum_functions.py +8 -6
- classiq/interface/generator/functions/builtins/core_library/exponentiation_functions.py +10 -4
- classiq/interface/generator/functions/builtins/internal_operators.py +7 -62
- classiq/interface/generator/functions/builtins/open_lib_functions.py +1627 -271
- classiq/interface/generator/functions/classical_type.py +27 -17
- classiq/interface/generator/model/preferences/preferences.py +4 -2
- classiq/interface/generator/synthesis_metadata/synthesis_duration.py +0 -4
- classiq/interface/model/bind_operation.py +3 -1
- classiq/interface/model/call_synthesis_data.py +2 -13
- classiq/interface/model/classical_if.py +3 -1
- classiq/interface/model/classical_parameter_declaration.py +13 -0
- classiq/interface/model/control.py +6 -8
- classiq/interface/model/inplace_binary_operation.py +3 -1
- classiq/interface/model/invert.py +3 -1
- classiq/interface/model/port_declaration.py +8 -1
- classiq/interface/model/power.py +3 -1
- classiq/interface/model/quantum_expressions/amplitude_loading_operation.py +4 -2
- classiq/interface/model/quantum_expressions/arithmetic_operation.py +3 -1
- classiq/interface/model/quantum_expressions/quantum_expression.py +11 -1
- classiq/interface/model/quantum_function_call.py +4 -10
- classiq/interface/model/quantum_function_declaration.py +26 -4
- classiq/interface/model/quantum_lambda_function.py +1 -20
- classiq/interface/model/quantum_statement.py +9 -2
- classiq/interface/model/quantum_type.py +6 -5
- classiq/interface/model/repeat.py +3 -1
- classiq/interface/model/resolvers/function_call_resolver.py +0 -5
- classiq/interface/model/statement_block.py +19 -16
- classiq/interface/model/validations/handles_validator.py +8 -2
- classiq/interface/model/variable_declaration_statement.py +3 -1
- classiq/interface/model/within_apply_operation.py +3 -1
- classiq/interface/server/routes.py +0 -5
- classiq/qmod/__init__.py +5 -2
- classiq/qmod/builtins/classical_execution_primitives.py +22 -2
- classiq/qmod/builtins/classical_functions.py +30 -35
- classiq/qmod/builtins/functions.py +263 -153
- classiq/qmod/builtins/operations.py +50 -26
- classiq/qmod/builtins/structs.py +50 -48
- classiq/qmod/declaration_inferrer.py +32 -27
- classiq/qmod/native/__init__.py +9 -0
- classiq/qmod/native/expression_to_qmod.py +8 -4
- classiq/qmod/native/pretty_printer.py +11 -18
- classiq/qmod/pretty_print/__init__.py +9 -0
- classiq/qmod/pretty_print/expression_to_python.py +221 -0
- classiq/qmod/pretty_print/pretty_printer.py +421 -0
- classiq/qmod/qmod_constant.py +7 -7
- classiq/qmod/qmod_parameter.py +57 -33
- classiq/qmod/qmod_struct.py +2 -2
- classiq/qmod/qmod_variable.py +40 -29
- classiq/qmod/quantum_callable.py +8 -4
- classiq/qmod/quantum_expandable.py +22 -15
- classiq/qmod/quantum_function.py +15 -4
- classiq/qmod/symbolic.py +73 -68
- classiq/qmod/symbolic_expr.py +1 -1
- classiq/qmod/symbolic_type.py +1 -4
- classiq/qmod/utilities.py +29 -0
- classiq/synthesis.py +15 -16
- {classiq-0.39.0.dist-info → classiq-0.41.0.dist-info}/METADATA +5 -4
- {classiq-0.39.0.dist-info → classiq-0.41.0.dist-info}/RECORD +95 -94
- classiq/interface/executor/error_mitigation.py +0 -6
- classiq/interface/generator/functions/builtins/core_library/chemistry_functions.py +0 -0
- classiq/interface/model/common_model_types.py +0 -23
- classiq/interface/model/quantum_expressions/control_state.py +0 -38
- classiq/interface/model/quantum_if_operation.py +0 -94
- {classiq-0.39.0.dist-info → classiq-0.41.0.dist-info}/WHEEL +0 -0
classiq/qmod/qmod_parameter.py
CHANGED
@@ -26,21 +26,50 @@ _T = TypeVar("_T")
|
|
26
26
|
|
27
27
|
|
28
28
|
if TYPE_CHECKING:
|
29
|
+
SymbolicSuperclass = SymbolicExpr
|
30
|
+
else:
|
31
|
+
SymbolicSuperclass = Symbolic
|
29
32
|
|
30
|
-
class QParam(SymbolicExpr, Generic[_T]):
|
31
|
-
pass
|
32
33
|
|
33
|
-
|
34
|
+
class CParam(SymbolicSuperclass):
|
35
|
+
pass
|
34
36
|
|
35
|
-
|
36
|
-
|
37
|
+
|
38
|
+
class CInt(CParam):
|
39
|
+
pass
|
37
40
|
|
38
41
|
|
39
|
-
class
|
42
|
+
class CReal(CParam):
|
40
43
|
pass
|
41
44
|
|
42
45
|
|
43
|
-
class
|
46
|
+
class CBool(CParam):
|
47
|
+
pass
|
48
|
+
|
49
|
+
|
50
|
+
_P = ParamSpec("_P")
|
51
|
+
|
52
|
+
|
53
|
+
class ArrayBase(Generic[_P]):
|
54
|
+
# Support comma-separated generic args in older Python versions
|
55
|
+
if sys.version_info[0:2] < (3, 10):
|
56
|
+
|
57
|
+
def __class_getitem__(cls, args) -> _GenericAlias:
|
58
|
+
return _GenericAlias(cls, args)
|
59
|
+
|
60
|
+
|
61
|
+
class CArray(CParam, ArrayBase[_P]):
|
62
|
+
if TYPE_CHECKING:
|
63
|
+
|
64
|
+
@property
|
65
|
+
def len(self) -> int: ...
|
66
|
+
|
67
|
+
|
68
|
+
class CParamScalar(CParam, SymbolicExpr):
|
69
|
+
pass
|
70
|
+
|
71
|
+
|
72
|
+
class CParamList(CParam):
|
44
73
|
def __init__(
|
45
74
|
self,
|
46
75
|
expr: str,
|
@@ -51,7 +80,14 @@ class QParamList(QParam):
|
|
51
80
|
self._qmodule = qmodule
|
52
81
|
self._list_type = list_type
|
53
82
|
|
54
|
-
def __getitem__(self, key: Any) ->
|
83
|
+
def __getitem__(self, key: Any) -> CParam:
|
84
|
+
if isinstance(key, slice):
|
85
|
+
start = key.start if key.start is not None else ""
|
86
|
+
stop = key.stop if key.stop is not None else ""
|
87
|
+
if key.step is not None:
|
88
|
+
key = f"{start}:{key.step}:{stop}"
|
89
|
+
else:
|
90
|
+
key = f"{start}:{stop}"
|
55
91
|
return create_param(
|
56
92
|
f"({self})[{key}]",
|
57
93
|
self._list_type.element_type,
|
@@ -64,11 +100,11 @@ class QParamList(QParam):
|
|
64
100
|
)
|
65
101
|
|
66
102
|
@property
|
67
|
-
def len(self) ->
|
68
|
-
return
|
103
|
+
def len(self) -> CParamScalar:
|
104
|
+
return CParamScalar(f"get_field({self}, 'len')")
|
69
105
|
|
70
106
|
|
71
|
-
class
|
107
|
+
class CParamStruct(CParam):
|
72
108
|
def __init__(
|
73
109
|
self, expr: str, struct_type: Struct, *, qmodule: ModelStateContainer
|
74
110
|
) -> None:
|
@@ -76,8 +112,8 @@ class QParamStruct(QParam):
|
|
76
112
|
self._qmodule = qmodule
|
77
113
|
self._struct_type = struct_type
|
78
114
|
|
79
|
-
def __getattr__(self, field_name: str) ->
|
80
|
-
return
|
115
|
+
def __getattr__(self, field_name: str) -> CParam:
|
116
|
+
return CParamStruct.get_field(
|
81
117
|
self._qmodule, str(self), self._struct_type.name, field_name
|
82
118
|
)
|
83
119
|
|
@@ -87,7 +123,7 @@ class QParamStruct(QParam):
|
|
87
123
|
variable_name: str,
|
88
124
|
struct_name: str,
|
89
125
|
field_name: str,
|
90
|
-
) ->
|
126
|
+
) -> CParam:
|
91
127
|
struct_decl = StructDeclaration.BUILTIN_STRUCT_DECLARATIONS.get(
|
92
128
|
struct_name, qmodule.type_decls.get(struct_name)
|
93
129
|
)
|
@@ -105,27 +141,15 @@ class QParamStruct(QParam):
|
|
105
141
|
)
|
106
142
|
|
107
143
|
|
108
|
-
_P = ParamSpec("_P")
|
109
|
-
|
110
|
-
|
111
|
-
class ArrayBase(Generic[_P]):
|
112
|
-
# Support comma-separated generic args in older Python versions
|
113
|
-
if sys.version_info[0:2] < (3, 10):
|
114
|
-
|
115
|
-
def __class_getitem__(cls, args) -> _GenericAlias:
|
116
|
-
return _GenericAlias(cls, args)
|
117
|
-
|
118
|
-
|
119
|
-
class Array(ArrayBase[_P]):
|
120
|
-
pass
|
121
|
-
|
122
|
-
|
123
144
|
def create_param(
|
124
145
|
expr_str: str, ctype: ClassicalType, qmodule: ModelStateContainer
|
125
|
-
) ->
|
146
|
+
) -> CParam:
|
126
147
|
if isinstance(ctype, (ClassicalList, ClassicalArray)):
|
127
|
-
return
|
148
|
+
return CParamList(expr_str, ctype, qmodule=qmodule)
|
128
149
|
elif isinstance(ctype, Struct):
|
129
|
-
return
|
150
|
+
return CParamStruct(expr_str, ctype, qmodule=qmodule)
|
130
151
|
else:
|
131
|
-
return
|
152
|
+
return CParamScalar(expr_str)
|
153
|
+
|
154
|
+
|
155
|
+
Array = CArray
|
classiq/qmod/qmod_struct.py
CHANGED
@@ -3,7 +3,7 @@ from typing import Any, Type
|
|
3
3
|
|
4
4
|
from typing_extensions import dataclass_transform
|
5
5
|
|
6
|
-
from classiq.interface.generator.functions.classical_type import
|
6
|
+
from classiq.interface.generator.functions.classical_type import CStructBase
|
7
7
|
|
8
8
|
|
9
9
|
def _qmod_val_to_expr_str(val: Any) -> str:
|
@@ -30,7 +30,7 @@ def struct(user_class: Type) -> Type:
|
|
30
30
|
|
31
31
|
user_dataclass = type(
|
32
32
|
user_class.__name__,
|
33
|
-
(
|
33
|
+
(CStructBase, dataclasses.dataclass(user_class)),
|
34
34
|
dict(),
|
35
35
|
)
|
36
36
|
user_dataclass.__repr__ = _new_repr # type:ignore[assignment]
|
classiq/qmod/qmod_variable.py
CHANGED
@@ -21,6 +21,7 @@ from typing import ( # type: ignore[attr-defined]
|
|
21
21
|
|
22
22
|
from typing_extensions import Annotated, ParamSpec, Self, _AnnotatedAlias
|
23
23
|
|
24
|
+
from classiq.interface.ast_node import SourceReference
|
24
25
|
from classiq.interface.generator.expressions.expression import Expression
|
25
26
|
from classiq.interface.generator.functions.port_declaration import (
|
26
27
|
PortDeclarationDirection,
|
@@ -45,11 +46,11 @@ from classiq.interface.model.quantum_type import (
|
|
45
46
|
)
|
46
47
|
|
47
48
|
from classiq.exceptions import ClassiqValueError
|
48
|
-
from classiq.qmod.qmod_parameter import ArrayBase,
|
49
|
+
from classiq.qmod.qmod_parameter import ArrayBase, CBool, CInt, CParam, CParamScalar
|
49
50
|
from classiq.qmod.quantum_callable import QCallable
|
50
51
|
from classiq.qmod.symbolic_expr import Symbolic, SymbolicExpr
|
51
52
|
from classiq.qmod.symbolic_type import SymbolicTypes
|
52
|
-
from classiq.qmod.utilities import version_portable_get_args
|
53
|
+
from classiq.qmod.utilities import get_source_ref, version_portable_get_args
|
53
54
|
|
54
55
|
ILLEGAL_SLICING_STEP_MSG = "Slicing with a step of a quantum variable is not supported"
|
55
56
|
SLICE_OUT_OF_BOUNDS_MSG = "Slice end index out of bounds"
|
@@ -82,8 +83,9 @@ def _no_current_expandable() -> Iterator[None]:
|
|
82
83
|
QCallable.CURRENT_EXPANDABLE = current_expandable
|
83
84
|
|
84
85
|
|
85
|
-
class QVar:
|
86
|
+
class QVar(Symbolic):
|
86
87
|
def __init__(self, name: str) -> None:
|
88
|
+
super().__init__(name)
|
87
89
|
self._name = name
|
88
90
|
if QCallable.CURRENT_EXPANDABLE is not None:
|
89
91
|
QCallable.CURRENT_EXPANDABLE.add_local_handle(
|
@@ -120,6 +122,9 @@ class QVar:
|
|
120
122
|
assert type_hint == cls or get_origin(type_hint) == cls
|
121
123
|
return PortDeclarationDirection.Inout
|
122
124
|
|
125
|
+
def __str__(self) -> str:
|
126
|
+
return str(self.get_handle_binding())
|
127
|
+
|
123
128
|
|
124
129
|
_Q = TypeVar("_Q", bound=QVar)
|
125
130
|
Output = Annotated[_Q, PortDeclarationDirection.Output]
|
@@ -131,7 +136,9 @@ class QScalar(QVar, SymbolicExpr):
|
|
131
136
|
QVar.__init__(self, name)
|
132
137
|
SymbolicExpr.__init__(self, name)
|
133
138
|
|
134
|
-
def _insert_arith_operation(
|
139
|
+
def _insert_arith_operation(
|
140
|
+
self, expr: SymbolicTypes, inplace: bool, source_ref: SourceReference
|
141
|
+
) -> None:
|
135
142
|
# Fixme: Arithmetic operations are not yet supported on slices (see CAD-12670)
|
136
143
|
if TYPE_CHECKING:
|
137
144
|
assert QCallable.CURRENT_EXPANDABLE is not None
|
@@ -140,16 +147,20 @@ class QScalar(QVar, SymbolicExpr):
|
|
140
147
|
expression=Expression(expr=str(expr)),
|
141
148
|
result_var=self.get_handle_binding(),
|
142
149
|
inplace_result=inplace,
|
150
|
+
source_ref=source_ref,
|
143
151
|
)
|
144
152
|
)
|
145
153
|
|
146
|
-
def _insert_amplitude_loading(
|
154
|
+
def _insert_amplitude_loading(
|
155
|
+
self, expr: SymbolicTypes, source_ref: SourceReference
|
156
|
+
) -> None:
|
147
157
|
if TYPE_CHECKING:
|
148
158
|
assert QCallable.CURRENT_EXPANDABLE is not None
|
149
159
|
QCallable.CURRENT_EXPANDABLE.append_statement_to_body(
|
150
160
|
AmplitudeLoadingOperation(
|
151
161
|
expression=Expression(expr=str(expr)),
|
152
162
|
result_var=self.get_handle_binding(),
|
163
|
+
source_ref=source_ref,
|
153
164
|
)
|
154
165
|
)
|
155
166
|
|
@@ -162,7 +173,7 @@ class QScalar(QVar, SymbolicExpr):
|
|
162
173
|
f"Invalid argument {other!r} for out-of-place arithmetic operation"
|
163
174
|
)
|
164
175
|
|
165
|
-
self._insert_arith_operation(other, False)
|
176
|
+
self._insert_arith_operation(other, False, get_source_ref(sys._getframe(1)))
|
166
177
|
return self
|
167
178
|
|
168
179
|
def __ixor__(self, other: Any) -> Self:
|
@@ -171,7 +182,7 @@ class QScalar(QVar, SymbolicExpr):
|
|
171
182
|
f"Invalid argument {other!r} for in-place arithmetic operation"
|
172
183
|
)
|
173
184
|
|
174
|
-
self._insert_arith_operation(other, True)
|
185
|
+
self._insert_arith_operation(other, True, get_source_ref(sys._getframe(1)))
|
175
186
|
return self
|
176
187
|
|
177
188
|
def __imul__(self, other: Any) -> Self:
|
@@ -180,7 +191,7 @@ class QScalar(QVar, SymbolicExpr):
|
|
180
191
|
f"Invalid argument {other!r} for out of ampltiude encoding operation"
|
181
192
|
)
|
182
193
|
|
183
|
-
self._insert_amplitude_loading(other)
|
194
|
+
self._insert_amplitude_loading(other, get_source_ref(sys._getframe(1)))
|
184
195
|
return self
|
185
196
|
|
186
197
|
|
@@ -207,18 +218,18 @@ class QNum(Generic[_P], QScalar):
|
|
207
218
|
def __init__(
|
208
219
|
self,
|
209
220
|
name: str,
|
210
|
-
size: Union[int,
|
211
|
-
is_signed: Union[bool,
|
212
|
-
fraction_digits: Union[int,
|
221
|
+
size: Union[int, CInt],
|
222
|
+
is_signed: Union[bool, CBool],
|
223
|
+
fraction_digits: Union[int, CInt],
|
213
224
|
):
|
214
225
|
pass
|
215
226
|
|
216
227
|
def __init__(
|
217
228
|
self,
|
218
229
|
name: str,
|
219
|
-
size: Union[int,
|
220
|
-
is_signed: Union[bool,
|
221
|
-
fraction_digits: Union[int,
|
230
|
+
size: Union[int, CInt, None] = None,
|
231
|
+
is_signed: Union[bool, CBool, None] = None,
|
232
|
+
fraction_digits: Union[int, CInt, None] = None,
|
222
233
|
):
|
223
234
|
if (
|
224
235
|
size is None
|
@@ -244,8 +255,8 @@ class QNum(Generic[_P], QScalar):
|
|
244
255
|
type_args = type_args[0]
|
245
256
|
if len(type_args) != 3:
|
246
257
|
raise ClassiqValueError(
|
247
|
-
"QNum receives three type arguments: QNum[size: int |
|
248
|
-
"is_signed: bool |
|
258
|
+
"QNum receives three type arguments: QNum[size: int | CInt, "
|
259
|
+
"is_signed: bool | CBool, fraction_digits: int | CInt]"
|
249
260
|
)
|
250
261
|
return cls.QMOD_TYPE(
|
251
262
|
size=Expression(expr=get_type_hint_expr(type_args[0])),
|
@@ -261,16 +272,16 @@ class QNum(Generic[_P], QScalar):
|
|
261
272
|
)
|
262
273
|
|
263
274
|
@property
|
264
|
-
def size(self) ->
|
265
|
-
return
|
275
|
+
def size(self) -> CParamScalar:
|
276
|
+
return CParamScalar(f"get_field({self._name}, 'size')")
|
266
277
|
|
267
278
|
@property
|
268
|
-
def fraction_digits(self) ->
|
269
|
-
return
|
279
|
+
def fraction_digits(self) -> CParamScalar:
|
280
|
+
return CParamScalar(f"get_field({self._name}, 'fraction_digits')")
|
270
281
|
|
271
282
|
@property
|
272
|
-
def is_signed(self) ->
|
273
|
-
return
|
283
|
+
def is_signed(self) -> CParamScalar:
|
284
|
+
return CParamScalar(f"get_field({self._name}, 'is_signed')")
|
274
285
|
|
275
286
|
# Support comma-separated generic args in older Python versions
|
276
287
|
if sys.version_info[0:2] < (3, 10):
|
@@ -284,10 +295,10 @@ class QArray(ArrayBase[_P], QVar):
|
|
284
295
|
self,
|
285
296
|
name: str,
|
286
297
|
element_type: _GenericAlias = QBit,
|
287
|
-
length: Optional[Union[int,
|
298
|
+
length: Optional[Union[int, CInt]] = None,
|
288
299
|
# TODO [CAD-18620]: improve type hints
|
289
300
|
slice_: Optional[Tuple[int, int]] = None,
|
290
|
-
index_: Optional[Union[int,
|
301
|
+
index_: Optional[Union[int, CInt]] = None,
|
291
302
|
) -> None:
|
292
303
|
if element_type is not QBit:
|
293
304
|
raise ClassiqValueError(UNSUPPORTED_ELEMENT_TYPE)
|
@@ -313,7 +324,7 @@ class QArray(ArrayBase[_P], QVar):
|
|
313
324
|
|
314
325
|
return HandleBinding(name=self._name)
|
315
326
|
|
316
|
-
def __getitem__(self, key: Union[slice, int,
|
327
|
+
def __getitem__(self, key: Union[slice, int, CInt]) -> "QArray":
|
317
328
|
if self._index is not None:
|
318
329
|
raise ClassiqValueError(QARRAY_ELEMENT_NOT_SUBSCRIPTABLE)
|
319
330
|
|
@@ -326,7 +337,7 @@ class QArray(ArrayBase[_P], QVar):
|
|
326
337
|
new_slice = self._get_new_slice(key.start, key.stop)
|
327
338
|
|
328
339
|
else:
|
329
|
-
if isinstance(key,
|
340
|
+
if isinstance(key, CParam) and not isinstance(key, CParamScalar):
|
330
341
|
raise ClassiqValueError("Non-classical parameter for slicing")
|
331
342
|
new_slice = self._get_new_slice(key, key + 1)
|
332
343
|
new_index = new_slice[0]
|
@@ -368,10 +379,10 @@ class QArray(ArrayBase[_P], QVar):
|
|
368
379
|
else:
|
369
380
|
|
370
381
|
@property
|
371
|
-
def len(self) ->
|
382
|
+
def len(self) -> CParamScalar:
|
372
383
|
if self._length is not None:
|
373
|
-
return
|
374
|
-
return
|
384
|
+
return CParamScalar(f"{self._length}")
|
385
|
+
return CParamScalar(f"get_field({self._name}, 'len')")
|
375
386
|
|
376
387
|
@classmethod
|
377
388
|
def to_qmod_quantum_type(cls, type_hint: Any) -> QuantumType:
|
classiq/qmod/quantum_callable.py
CHANGED
@@ -12,6 +12,7 @@ from typing import ( # type: ignore[attr-defined]
|
|
12
12
|
|
13
13
|
from typing_extensions import ParamSpec
|
14
14
|
|
15
|
+
from classiq.interface.ast_node import SourceReference
|
15
16
|
from classiq.interface.model.quantum_function_call import QuantumFunctionCall
|
16
17
|
from classiq.interface.model.quantum_function_declaration import (
|
17
18
|
QuantumFunctionDeclaration,
|
@@ -19,7 +20,8 @@ from classiq.interface.model.quantum_function_declaration import (
|
|
19
20
|
from classiq.interface.model.quantum_statement import QuantumStatement
|
20
21
|
from classiq.interface.model.quantum_type import QuantumType
|
21
22
|
|
22
|
-
from classiq.qmod.qmod_parameter import
|
23
|
+
from classiq.qmod.qmod_parameter import CInt
|
24
|
+
from classiq.qmod.utilities import get_source_ref
|
23
25
|
|
24
26
|
if TYPE_CHECKING:
|
25
27
|
from classiq.qmod.quantum_expandable import QTerminalCallable
|
@@ -39,11 +41,13 @@ class QExpandableInterface(ABC):
|
|
39
41
|
|
40
42
|
class QCallable(Generic[P], ABC):
|
41
43
|
CURRENT_EXPANDABLE: ClassVar[Optional[QExpandableInterface]] = None
|
44
|
+
FRAME_DEPTH = 1
|
42
45
|
|
43
46
|
def __call__(self, *args: Any, **kwargs: Any) -> None:
|
44
47
|
assert QCallable.CURRENT_EXPANDABLE is not None
|
48
|
+
source_ref = get_source_ref(sys._getframe(self.FRAME_DEPTH))
|
45
49
|
QCallable.CURRENT_EXPANDABLE.append_statement_to_body(
|
46
|
-
self.create_quantum_function_call(*args, **kwargs)
|
50
|
+
self.create_quantum_function_call(source_ref, *args, **kwargs)
|
47
51
|
)
|
48
52
|
return
|
49
53
|
|
@@ -60,7 +64,7 @@ class QCallable(Generic[P], ABC):
|
|
60
64
|
|
61
65
|
@abstractmethod
|
62
66
|
def create_quantum_function_call(
|
63
|
-
self, *args: Any, **kwargs: Any
|
67
|
+
self, source_ref_: SourceReference, *args: Any, **kwargs: Any
|
64
68
|
) -> QuantumFunctionCall:
|
65
69
|
raise NotImplementedError()
|
66
70
|
|
@@ -71,5 +75,5 @@ class QCallableList(QCallable, Generic[P], ABC):
|
|
71
75
|
@property
|
72
76
|
def len(self) -> int: ...
|
73
77
|
|
74
|
-
def __getitem__(self, key: Union[slice, int,
|
78
|
+
def __getitem__(self, key: Union[slice, int, CInt]) -> "QTerminalCallable":
|
75
79
|
raise NotImplementedError()
|
@@ -17,6 +17,7 @@ from typing import (
|
|
17
17
|
|
18
18
|
from typing_extensions import Self
|
19
19
|
|
20
|
+
from classiq.interface.ast_node import SourceReference
|
20
21
|
from classiq.interface.generator.expressions.expression import Expression
|
21
22
|
from classiq.interface.model.classical_parameter_declaration import (
|
22
23
|
ClassicalParameterDeclaration,
|
@@ -42,12 +43,12 @@ from classiq.interface.model.variable_declaration_statement import (
|
|
42
43
|
from classiq.exceptions import ClassiqValueError
|
43
44
|
from classiq.qmod.model_state_container import QMODULE, ModelStateContainer
|
44
45
|
from classiq.qmod.qmod_constant import QConstant
|
45
|
-
from classiq.qmod.qmod_parameter import
|
46
|
+
from classiq.qmod.qmod_parameter import CInt, CParam, CParamScalar, create_param
|
46
47
|
from classiq.qmod.qmod_variable import QVar, create_qvar_for_port_decl
|
47
48
|
from classiq.qmod.quantum_callable import QCallable, QExpandableInterface
|
48
49
|
from classiq.qmod.utilities import mangle_keyword
|
49
50
|
|
50
|
-
ArgType = Union[
|
51
|
+
ArgType = Union[CParam, QVar, QCallable]
|
51
52
|
|
52
53
|
|
53
54
|
class QExpandable(QCallable, QExpandableInterface, ABC):
|
@@ -80,8 +81,9 @@ class QExpandable(QCallable, QExpandableInterface, ABC):
|
|
80
81
|
)
|
81
82
|
|
82
83
|
def expand(self) -> None:
|
83
|
-
|
84
|
-
self
|
84
|
+
if self not in QExpandable.STACK:
|
85
|
+
with self:
|
86
|
+
self._py_callable(*self._get_positional_args())
|
85
87
|
|
86
88
|
def infer_rename_params(self) -> Dict[str, str]:
|
87
89
|
return {}
|
@@ -109,9 +111,11 @@ class QExpandable(QCallable, QExpandableInterface, ABC):
|
|
109
111
|
return result
|
110
112
|
|
111
113
|
def create_quantum_function_call(
|
112
|
-
self, *args: Any, **kwargs: Any
|
114
|
+
self, source_ref_: SourceReference, *args: Any, **kwargs: Any
|
113
115
|
) -> QuantumFunctionCall:
|
114
|
-
return _create_quantum_function_call(
|
116
|
+
return _create_quantum_function_call(
|
117
|
+
self.func_decl, None, source_ref_, *args, **kwargs
|
118
|
+
)
|
115
119
|
|
116
120
|
|
117
121
|
class QLambdaFunction(QExpandable):
|
@@ -138,7 +142,7 @@ class QTerminalCallable(QCallable):
|
|
138
142
|
def __init__(
|
139
143
|
self,
|
140
144
|
decl: QuantumFunctionDeclaration,
|
141
|
-
index_: Optional[Union[int,
|
145
|
+
index_: Optional[Union[int, CParamScalar]] = None,
|
142
146
|
) -> None:
|
143
147
|
self._decl = decl
|
144
148
|
self._index = index_
|
@@ -147,12 +151,12 @@ class QTerminalCallable(QCallable):
|
|
147
151
|
def is_list(self) -> bool:
|
148
152
|
return isinstance(self._decl, QuantumOperandDeclaration) and self._decl.is_list
|
149
153
|
|
150
|
-
def __getitem__(self, key: Union[slice, int,
|
154
|
+
def __getitem__(self, key: Union[slice, int, CInt]) -> "QTerminalCallable":
|
151
155
|
if not self.is_list:
|
152
156
|
raise ClassiqValueError("Cannot index a non-list operand")
|
153
157
|
if isinstance(key, slice):
|
154
158
|
raise NotImplementedError("Operand lists don't support slicing")
|
155
|
-
if isinstance(key,
|
159
|
+
if isinstance(key, CParam) and not isinstance(key, CParamScalar):
|
156
160
|
raise ClassiqValueError("Non-classical parameter for slicing")
|
157
161
|
return QTerminalCallable(self._decl, key)
|
158
162
|
|
@@ -169,24 +173,24 @@ class QTerminalCallable(QCallable):
|
|
169
173
|
else:
|
170
174
|
|
171
175
|
@property
|
172
|
-
def len(self) ->
|
176
|
+
def len(self) -> CParamScalar:
|
173
177
|
if not self.is_list:
|
174
178
|
raise ClassiqValueError("Cannot get length of a non-list operand")
|
175
|
-
return
|
179
|
+
return CParamScalar(f"get_field({self.func_decl.name}, 'len')")
|
176
180
|
|
177
181
|
@property
|
178
182
|
def func_decl(self) -> QuantumFunctionDeclaration:
|
179
183
|
return self._decl
|
180
184
|
|
181
185
|
def create_quantum_function_call(
|
182
|
-
self, *args: Any, **kwargs: Any
|
186
|
+
self, source_ref_: SourceReference, *args: Any, **kwargs: Any
|
183
187
|
) -> QuantumFunctionCall:
|
184
188
|
if self.is_list and self._index is None:
|
185
189
|
raise ClassiqValueError(
|
186
190
|
f"Quantum operand {self.func_decl.name!r} is a list and must be indexed"
|
187
191
|
)
|
188
192
|
return _create_quantum_function_call(
|
189
|
-
self.func_decl, self._index, *args, **kwargs
|
193
|
+
self.func_decl, self._index, source_ref_, *args, **kwargs
|
190
194
|
)
|
191
195
|
|
192
196
|
|
@@ -278,7 +282,8 @@ def _prepare_args(
|
|
278
282
|
|
279
283
|
def _create_quantum_function_call(
|
280
284
|
decl_: QuantumFunctionDeclaration,
|
281
|
-
index_: Optional[Union[
|
285
|
+
index_: Optional[Union[CParamScalar, int]] = None,
|
286
|
+
source_ref_: Optional[SourceReference] = None,
|
282
287
|
*args: Any,
|
283
288
|
**kwargs: Any,
|
284
289
|
) -> QuantumFunctionCall:
|
@@ -306,4 +311,6 @@ def _create_quantum_function_call(
|
|
306
311
|
index=Expression(expr=str(index_)), name=function_ident
|
307
312
|
)
|
308
313
|
|
309
|
-
return QuantumFunctionCall(
|
314
|
+
return QuantumFunctionCall(
|
315
|
+
function=function_ident, positional_args=prepared_args, source_ref=source_ref_
|
316
|
+
)
|
classiq/qmod/quantum_function.py
CHANGED
@@ -1,8 +1,10 @@
|
|
1
1
|
import ast
|
2
2
|
import functools
|
3
|
+
from inspect import isclass
|
3
4
|
from typing import Any, Callable, Dict, List, Optional, Tuple, get_origin
|
4
5
|
|
5
6
|
from classiq.interface.executor.execution_preferences import ExecutionPreferences
|
7
|
+
from classiq.interface.generator.functions.classical_type import CStructBase
|
6
8
|
from classiq.interface.generator.model.constraints import Constraints
|
7
9
|
from classiq.interface.generator.model.preferences.preferences import Preferences
|
8
10
|
from classiq.interface.model.model import Model, SerializedModel
|
@@ -15,7 +17,7 @@ from classiq.exceptions import ClassiqError
|
|
15
17
|
from classiq.qmod.classical_function import CFunc
|
16
18
|
from classiq.qmod.declaration_inferrer import infer_func_decl
|
17
19
|
from classiq.qmod.qmod_constant import QConstant
|
18
|
-
from classiq.qmod.qmod_parameter import
|
20
|
+
from classiq.qmod.qmod_parameter import CArray, CParam
|
19
21
|
from classiq.qmod.qmod_variable import QVar
|
20
22
|
from classiq.qmod.quantum_callable import QCallable, QCallableList
|
21
23
|
from classiq.qmod.quantum_expandable import QExpandable, QTerminalCallable
|
@@ -44,6 +46,8 @@ def create_model(
|
|
44
46
|
|
45
47
|
|
46
48
|
class QFunc(QExpandable):
|
49
|
+
FRAME_DEPTH = 2
|
50
|
+
|
47
51
|
def __init__(self, py_callable: Callable) -> None:
|
48
52
|
_validate_no_gen_params(py_callable.__annotations__)
|
49
53
|
super().__init__(py_callable)
|
@@ -94,7 +98,7 @@ class QFunc(QExpandable):
|
|
94
98
|
return
|
95
99
|
self.expand()
|
96
100
|
self._qmodule.native_defs[self.func_decl.name] = NativeFunctionDefinition(
|
97
|
-
**self.func_decl.
|
101
|
+
**{**self.func_decl.dict(), **{"body": self.body}}
|
98
102
|
)
|
99
103
|
|
100
104
|
def _add_constants_from_classical_code(
|
@@ -144,7 +148,10 @@ ILLEGAL_PARAM_ERROR = "Unsupported type hint '{annotation}' for argument '{name}
|
|
144
148
|
|
145
149
|
|
146
150
|
class IllegalParamsError(ClassiqError):
|
147
|
-
_HINT =
|
151
|
+
_HINT = (
|
152
|
+
"\nNote - QMOD functions can declare classical parameters using the type hints "
|
153
|
+
"'CInt', 'CReal', 'CBool', and 'CArray'."
|
154
|
+
)
|
148
155
|
|
149
156
|
def __init__(self, message: str) -> None:
|
150
157
|
super().__init__(message + self._HINT)
|
@@ -156,7 +163,11 @@ def _validate_no_gen_params(annotations: Dict[str, Any]) -> None:
|
|
156
163
|
for name, annotation in annotations.items()
|
157
164
|
if not (
|
158
165
|
name == "return"
|
159
|
-
or
|
166
|
+
or isclass(annotation)
|
167
|
+
and issubclass(annotation, CParam)
|
168
|
+
or isclass(annotation)
|
169
|
+
and issubclass(annotation, CStructBase)
|
170
|
+
or get_origin(annotation) is CArray
|
160
171
|
or (get_origin(annotation) or annotation) is QCallable
|
161
172
|
or (get_origin(annotation) or annotation) is QCallableList
|
162
173
|
or QVar.from_type_hint(annotation) is not None
|