classiq 0.47.0__py3-none-any.whl → 0.48.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/applications/combinatorial_helpers/pauli_helpers/pauli_utils.py +2 -7
- classiq/applications/grover/grover_model_constructor.py +2 -1
- classiq/execution/execution_session.py +40 -9
- classiq/execution/jobs.py +18 -6
- classiq/interface/_version.py +1 -1
- classiq/interface/execution/primitives.py +9 -1
- classiq/interface/executor/iqae_result.py +3 -3
- classiq/interface/executor/result.py +3 -1
- classiq/interface/generator/expressions/expression.py +8 -0
- classiq/interface/generator/functions/type_name.py +1 -3
- classiq/interface/generator/synthesis_metadata/synthesis_execution_data.py +17 -3
- classiq/interface/ide/visual_model.py +3 -4
- classiq/interface/model/bind_operation.py +0 -3
- classiq/interface/model/port_declaration.py +1 -12
- classiq/interface/model/quantum_expressions/arithmetic_operation.py +34 -6
- classiq/interface/model/quantum_lambda_function.py +4 -1
- classiq/interface/model/quantum_statement.py +16 -1
- classiq/interface/model/quantum_variable_declaration.py +0 -22
- classiq/interface/server/global_versions.py +4 -4
- classiq/model_expansions/capturing/propagated_var_stack.py +5 -2
- classiq/model_expansions/closure.py +7 -2
- classiq/model_expansions/evaluators/quantum_type_utils.py +0 -7
- classiq/model_expansions/generative_functions.py +146 -28
- classiq/model_expansions/interpreter.py +11 -5
- classiq/model_expansions/quantum_operations/classicalif.py +27 -10
- classiq/model_expansions/quantum_operations/control.py +22 -15
- classiq/model_expansions/quantum_operations/emitter.py +60 -5
- classiq/model_expansions/quantum_operations/expression_operation.py +25 -16
- classiq/model_expansions/quantum_operations/inplace_binary_operation.py +167 -95
- classiq/model_expansions/quantum_operations/invert.py +12 -6
- classiq/model_expansions/quantum_operations/phase.py +15 -3
- classiq/model_expansions/quantum_operations/power.py +9 -8
- classiq/model_expansions/quantum_operations/quantum_assignment_operation.py +20 -5
- classiq/model_expansions/quantum_operations/quantum_function_call.py +1 -1
- classiq/model_expansions/quantum_operations/repeat.py +32 -13
- classiq/model_expansions/quantum_operations/within_apply.py +19 -6
- classiq/model_expansions/scope.py +16 -5
- classiq/model_expansions/scope_initialization.py +11 -1
- classiq/model_expansions/sympy_conversion/expression_to_sympy.py +23 -1
- classiq/model_expansions/visitors/variable_references.py +11 -7
- classiq/qmod/builtins/__init__.py +10 -0
- classiq/qmod/builtins/constants.py +10 -0
- classiq/qmod/builtins/functions/state_preparation.py +4 -1
- classiq/qmod/builtins/operations.py +43 -163
- classiq/qmod/create_model_function.py +1 -1
- classiq/qmod/generative.py +14 -5
- classiq/qmod/native/pretty_printer.py +9 -5
- classiq/qmod/pretty_print/pretty_printer.py +8 -4
- classiq/qmod/qmod_constant.py +28 -18
- classiq/qmod/qmod_variable.py +43 -23
- classiq/qmod/quantum_expandable.py +14 -1
- classiq/qmod/semantics/static_semantics_visitor.py +10 -0
- classiq/qmod/semantics/validation/constants_validation.py +16 -0
- {classiq-0.47.0.dist-info → classiq-0.48.0.dist-info}/METADATA +3 -1
- {classiq-0.47.0.dist-info → classiq-0.48.0.dist-info}/RECORD +56 -54
- {classiq-0.47.0.dist-info → classiq-0.48.0.dist-info}/WHEEL +0 -0
@@ -1,11 +1,10 @@
|
|
1
1
|
import itertools
|
2
2
|
from collections import UserDict
|
3
|
+
from contextlib import contextmanager
|
3
4
|
from dataclasses import dataclass
|
4
5
|
from functools import singledispatch
|
5
6
|
from typing import TYPE_CHECKING, Any, Dict, Iterator, Optional, Type, TypeVar, Union
|
6
7
|
|
7
|
-
from typing_extensions import Self
|
8
|
-
|
9
8
|
from classiq.interface.exceptions import (
|
10
9
|
ClassiqExpansionError,
|
11
10
|
ClassiqInternalExpansionError,
|
@@ -180,13 +179,13 @@ class Scope(EvaluatedUserDict):
|
|
180
179
|
data: Optional[Dict[str, Evaluated]] = None,
|
181
180
|
/,
|
182
181
|
*,
|
183
|
-
parent: Optional[
|
182
|
+
parent: Optional["Scope"] = None,
|
184
183
|
) -> None:
|
185
184
|
super().__init__(data or {})
|
186
|
-
self._parent: Optional[
|
185
|
+
self._parent: Optional["Scope"] = parent
|
187
186
|
|
188
187
|
@property
|
189
|
-
def parent(self) -> Optional[
|
188
|
+
def parent(self) -> Optional["Scope"]:
|
190
189
|
return self._parent
|
191
190
|
|
192
191
|
def __getitem__(self, name: str) -> Evaluated:
|
@@ -224,3 +223,15 @@ class Scope(EvaluatedUserDict):
|
|
224
223
|
(self.data or {}) | (other.data or {}),
|
225
224
|
parent=parent,
|
226
225
|
)
|
226
|
+
|
227
|
+
def _copy(self) -> "Scope":
|
228
|
+
return Scope(
|
229
|
+
self.data, parent=None if self._parent is None else self._parent.copy()
|
230
|
+
)
|
231
|
+
|
232
|
+
@contextmanager
|
233
|
+
def freeze(self) -> Iterator[None]:
|
234
|
+
previous = self._copy()
|
235
|
+
yield
|
236
|
+
self.data = previous.data
|
237
|
+
self._parent = previous._parent
|
@@ -1,5 +1,6 @@
|
|
1
1
|
from typing import List, Sequence
|
2
2
|
|
3
|
+
from classiq.interface.exceptions import ClassiqError
|
3
4
|
from classiq.interface.generator.constant import Constant
|
4
5
|
from classiq.interface.generator.expressions.expression_constants import (
|
5
6
|
CPARAM_EXECUTION_SUFFIX,
|
@@ -22,6 +23,7 @@ from classiq.model_expansions.evaluators.parameter_types import (
|
|
22
23
|
)
|
23
24
|
from classiq.model_expansions.expression_renamer import ExpressionRenamer
|
24
25
|
from classiq.model_expansions.scope import Evaluated, QuantumSymbol, Scope
|
26
|
+
from classiq.qmod.builtins import BUILTIN_CONSTANTS
|
25
27
|
from classiq.qmod.builtins.functions import (
|
26
28
|
CORE_LIB_DECLS,
|
27
29
|
OPEN_LIB_DECLS,
|
@@ -71,7 +73,7 @@ def _add_generative_functions_to_scope(
|
|
71
73
|
name=function.func_decl.name,
|
72
74
|
positional_arg_declarations=function.func_decl.positional_arg_declarations,
|
73
75
|
scope=Scope(parent=scope),
|
74
|
-
|
76
|
+
generative_blocks={"body": function},
|
75
77
|
)
|
76
78
|
)
|
77
79
|
|
@@ -104,6 +106,14 @@ def _init_builtins_scope(scope: Scope) -> None:
|
|
104
106
|
is_atomic=True,
|
105
107
|
)
|
106
108
|
)
|
109
|
+
for constant in BUILTIN_CONSTANTS:
|
110
|
+
value = constant.value
|
111
|
+
if not value.is_evaluated():
|
112
|
+
raise ClassiqError(
|
113
|
+
f"Unevaluated built-in constants not supported. Offending constant: "
|
114
|
+
f"{constant.name} = {value}"
|
115
|
+
)
|
116
|
+
scope[constant.name] = Evaluated(value=value.value.value)
|
107
117
|
|
108
118
|
|
109
119
|
def add_entry_point_params_to_scope(
|
@@ -1,5 +1,5 @@
|
|
1
1
|
import ast
|
2
|
-
from typing import TYPE_CHECKING, Dict, Type
|
2
|
+
from typing import TYPE_CHECKING, Dict, Type, cast
|
3
3
|
|
4
4
|
from classiq.interface.exceptions import ClassiqExpansionError
|
5
5
|
|
@@ -116,6 +116,9 @@ class ExpressionSympyTranslator(ast.NodeTransformer):
|
|
116
116
|
return self.generic_visit(node)
|
117
117
|
|
118
118
|
def visit_Call(self, node: ast.Call) -> ast.AST:
|
119
|
+
if isinstance(node.func, ast.Name) and node.func.id == "Piecewise":
|
120
|
+
return self._visit_piecewise(node)
|
121
|
+
|
119
122
|
if (
|
120
123
|
not isinstance(node.func, ast.Name)
|
121
124
|
or node.func.id not in self.SPECIAL_FUNCTIONS
|
@@ -128,6 +131,25 @@ class ExpressionSympyTranslator(ast.NodeTransformer):
|
|
128
131
|
keywords=[self.visit(arg) for arg in node.keywords],
|
129
132
|
)
|
130
133
|
|
134
|
+
def _visit_piecewise(self, node: ast.Call) -> ast.AST:
|
135
|
+
# sympy Piecewise expression may include bitwise operations:
|
136
|
+
# Piecewise((0, Eq(x, 0)), (0.5, Eq(x, 1) | Eq(x, 2)), (1, True))
|
137
|
+
# ^
|
138
|
+
# We should avoid converting these to 'BitwiseOr' and such.
|
139
|
+
return ast.Call(
|
140
|
+
func=node.func,
|
141
|
+
args=[
|
142
|
+
ast.Tuple(
|
143
|
+
elts=(
|
144
|
+
self.generic_visit(cast(ast.Tuple, arg).elts[0]),
|
145
|
+
cast(ast.Tuple, arg).elts[1],
|
146
|
+
)
|
147
|
+
)
|
148
|
+
for arg in node.args
|
149
|
+
],
|
150
|
+
keywords=node.keywords,
|
151
|
+
)
|
152
|
+
|
131
153
|
def visit_Subscript(self, node: ast.Subscript) -> ast.AST:
|
132
154
|
if isinstance(node.slice, ast.Slice):
|
133
155
|
if node.slice.lower is not None:
|
@@ -1,6 +1,6 @@
|
|
1
1
|
import ast
|
2
2
|
from contextlib import contextmanager
|
3
|
-
from typing import Dict, Iterator,
|
3
|
+
from typing import Dict, Iterator, List, Optional, Union
|
4
4
|
|
5
5
|
from classiq.interface.exceptions import (
|
6
6
|
ClassiqExpansionError,
|
@@ -23,10 +23,14 @@ from classiq.interface.model.handle_binding import (
|
|
23
23
|
|
24
24
|
class VarRefCollector(ast.NodeVisitor):
|
25
25
|
def __init__(self, ignore_duplicated_handles: bool = False) -> None:
|
26
|
-
self.
|
26
|
+
self._var_handles: Dict[HandleBinding, bool] = {}
|
27
27
|
self._ignore_duplicated_handles = ignore_duplicated_handles
|
28
28
|
self._is_nested = False
|
29
29
|
|
30
|
+
@property
|
31
|
+
def var_handles(self) -> List[HandleBinding]:
|
32
|
+
return list(self._var_handles)
|
33
|
+
|
30
34
|
def visit(self, node: ast.AST) -> Union[
|
31
35
|
SubscriptHandleBinding,
|
32
36
|
SlicedHandleBinding,
|
@@ -35,8 +39,8 @@ class VarRefCollector(ast.NodeVisitor):
|
|
35
39
|
None,
|
36
40
|
]:
|
37
41
|
res = super().visit(node)
|
38
|
-
if not self._ignore_duplicated_handles and len(self.
|
39
|
-
{handle.name for handle in self.
|
42
|
+
if not self._ignore_duplicated_handles and len(self._var_handles) != len(
|
43
|
+
{handle.name for handle in self._var_handles}
|
40
44
|
):
|
41
45
|
raise ClassiqExpansionError(
|
42
46
|
"Multiple non-identical variable references in an expression are not supported."
|
@@ -71,7 +75,7 @@ class VarRefCollector(ast.NodeVisitor):
|
|
71
75
|
raise ClassiqInternalExpansionError("Unevaluated slice.")
|
72
76
|
|
73
77
|
if not self._is_nested:
|
74
|
-
self.
|
78
|
+
self._var_handles[handle] = True
|
75
79
|
return handle
|
76
80
|
|
77
81
|
def visit_Attribute(self, node: ast.Attribute) -> Optional[FieldHandleBinding]:
|
@@ -84,7 +88,7 @@ class VarRefCollector(ast.NodeVisitor):
|
|
84
88
|
field=node.attr,
|
85
89
|
)
|
86
90
|
if not self._is_nested:
|
87
|
-
self.
|
91
|
+
self._var_handles[handle] = True
|
88
92
|
return handle
|
89
93
|
|
90
94
|
def visit_Name(self, node: ast.Name) -> Optional[HandleBinding]:
|
@@ -94,7 +98,7 @@ class VarRefCollector(ast.NodeVisitor):
|
|
94
98
|
return None
|
95
99
|
handle = HandleBinding(name=node.id)
|
96
100
|
if not self._is_nested:
|
97
|
-
self.
|
101
|
+
self._var_handles[handle] = True
|
98
102
|
return handle
|
99
103
|
|
100
104
|
@contextmanager
|
@@ -6,6 +6,8 @@ from .classical_execution_primitives import (
|
|
6
6
|
)
|
7
7
|
from .classical_functions import * # noqa: F403
|
8
8
|
from .classical_functions import __all__ as _builtin_classical_functions
|
9
|
+
from .constants import * # noqa: F403
|
10
|
+
from .constants import __all__ as _builtin_constants
|
9
11
|
from .enums import * # noqa: F403
|
10
12
|
from .enums import __all__ as _builtin_enums
|
11
13
|
from .functions import * # noqa: F403
|
@@ -18,6 +20,13 @@ from .structs import __all__ as _builtin_structs
|
|
18
20
|
FinanceFunctionInput.update_forward_refs(
|
19
21
|
FinanceFunctionType=FinanceFunctionType # noqa: F405
|
20
22
|
)
|
23
|
+
BUILTIN_CONSTANTS = [
|
24
|
+
constant._get_constant_node()
|
25
|
+
for constant in [
|
26
|
+
SIGNED, # noqa: F405
|
27
|
+
UNSIGNED, # noqa: F405
|
28
|
+
]
|
29
|
+
]
|
21
30
|
|
22
31
|
__all__ = (
|
23
32
|
_builtin_enums
|
@@ -26,4 +35,5 @@ __all__ = (
|
|
26
35
|
+ _builtin_operations
|
27
36
|
+ _builtin_classical_execution_primitives
|
28
37
|
+ _builtin_classical_functions
|
38
|
+
+ _builtin_constants
|
29
39
|
)
|
@@ -340,7 +340,10 @@ def inplace_prepare_int(value: CInt, target: QArray[QBit]) -> None:
|
|
340
340
|
|
341
341
|
|
342
342
|
@qfunc(external=True)
|
343
|
-
def prepare_int(
|
343
|
+
def prepare_int(
|
344
|
+
value: CInt,
|
345
|
+
out: Output[QNum[Literal["floor(log(value, 2)) + 1"], Literal[False], Literal[0]]],
|
346
|
+
) -> None:
|
344
347
|
"""
|
345
348
|
[Qmod Classiq-library function]
|
346
349
|
|
@@ -1,17 +1,13 @@
|
|
1
1
|
import inspect
|
2
2
|
import sys
|
3
|
-
import warnings
|
4
3
|
from types import FrameType
|
5
4
|
from typing import (
|
6
|
-
TYPE_CHECKING,
|
7
5
|
Any,
|
8
6
|
Callable,
|
9
7
|
Final,
|
10
8
|
List,
|
11
9
|
Mapping,
|
12
|
-
Optional,
|
13
10
|
Union,
|
14
|
-
overload,
|
15
11
|
)
|
16
12
|
|
17
13
|
from classiq.interface.exceptions import ClassiqValueError
|
@@ -80,57 +76,33 @@ def if_(
|
|
80
76
|
_validate_operand(else_)
|
81
77
|
assert QCallable.CURRENT_EXPANDABLE is not None
|
82
78
|
source_ref = get_source_ref(sys._getframe(1))
|
83
|
-
QCallable.CURRENT_EXPANDABLE.append_statement_to_body(
|
84
|
-
ClassicalIf(
|
85
|
-
condition=Expression(expr=str(condition)),
|
86
|
-
then=_operand_to_body(then, "then"),
|
87
|
-
else_=_operand_to_body(else_, "else") if else_ != _MISSING_VALUE else [], # type: ignore[arg-type]
|
88
|
-
source_ref=source_ref,
|
89
|
-
)
|
90
|
-
)
|
91
79
|
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
ctrl: SymbolicExpr, stmt_block: Union[QCallable, Callable[[], None]]
|
103
|
-
) -> None:
|
104
|
-
pass
|
80
|
+
if_stmt = ClassicalIf(
|
81
|
+
condition=Expression(expr=str(condition)),
|
82
|
+
then=_operand_to_body(then, "then"),
|
83
|
+
else_=_operand_to_body(else_, "else") if else_ != _MISSING_VALUE else [], # type: ignore[arg-type]
|
84
|
+
source_ref=source_ref,
|
85
|
+
)
|
86
|
+
if_stmt.set_generative_block("then", then)
|
87
|
+
if callable(else_):
|
88
|
+
if_stmt.set_generative_block("else", else_)
|
89
|
+
QCallable.CURRENT_EXPANDABLE.append_statement_to_body(if_stmt)
|
105
90
|
|
106
91
|
|
107
92
|
def control(
|
108
93
|
ctrl: Union[SymbolicExpr, QBit, QArray[QBit]],
|
109
|
-
stmt_block:
|
110
|
-
operand: Optional[Union[QCallable, Callable[[], None]]] = None,
|
94
|
+
stmt_block: Union[QCallable, Callable[[], None]],
|
111
95
|
) -> None:
|
112
|
-
if operand is not None:
|
113
|
-
warnings.warn(
|
114
|
-
"Parameter 'operand' of function 'control' has been renamed to "
|
115
|
-
"'stmt_block'. Parameter 'operand' will be deprecated in a future "
|
116
|
-
"release.\nHint: Change `control(ctrl=..., operand=...)` to "
|
117
|
-
"`control(ctrl=..., stmt_block=...)` or `control(..., ...)`.",
|
118
|
-
category=DeprecationWarning,
|
119
|
-
stacklevel=2,
|
120
|
-
)
|
121
|
-
stmt_block = operand
|
122
|
-
if TYPE_CHECKING:
|
123
|
-
assert stmt_block is not None
|
124
96
|
_validate_operand(stmt_block)
|
125
97
|
assert QCallable.CURRENT_EXPANDABLE is not None
|
126
98
|
source_ref = get_source_ref(sys._getframe(1))
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
|
131
|
-
source_ref=source_ref,
|
132
|
-
)
|
99
|
+
control_stmt = Control(
|
100
|
+
expression=Expression(expr=str(ctrl)),
|
101
|
+
body=_operand_to_body(stmt_block, "stmt_block"),
|
102
|
+
source_ref=source_ref,
|
133
103
|
)
|
104
|
+
control_stmt.set_generative_block("body", stmt_block)
|
105
|
+
QCallable.CURRENT_EXPANDABLE.append_statement_to_body(control_stmt)
|
134
106
|
|
135
107
|
|
136
108
|
def inplace_add(
|
@@ -165,56 +137,22 @@ def inplace_xor(
|
|
165
137
|
)
|
166
138
|
|
167
139
|
|
168
|
-
@overload # FIXME: Remove overloading (CAD-21932)
|
169
140
|
def within_apply(
|
170
141
|
within: Callable[[], None],
|
171
142
|
apply: Callable[[], None],
|
172
143
|
) -> None:
|
173
|
-
pass
|
174
|
-
|
175
|
-
|
176
|
-
@overload
|
177
|
-
def within_apply(
|
178
|
-
within: Callable[[], List[None]],
|
179
|
-
apply: Callable[[], List[None]],
|
180
|
-
) -> None:
|
181
|
-
pass
|
182
|
-
|
183
|
-
|
184
|
-
def within_apply( # type:ignore[misc]
|
185
|
-
within: Optional[Callable[[], None]] = None,
|
186
|
-
apply: Optional[Callable[[], None]] = None,
|
187
|
-
compute: Optional[Callable[[], None]] = None,
|
188
|
-
action: Optional[Callable[[], None]] = None,
|
189
|
-
) -> None:
|
190
|
-
if compute is not None or action is not None:
|
191
|
-
warnings.warn(
|
192
|
-
"Parameters 'compute' and 'action' of function 'within_apply' have "
|
193
|
-
"been renamed to 'within' and 'apply' respectively. Parameters 'compute' "
|
194
|
-
"and 'action' will be deprecated in a future release.\nHint: Change "
|
195
|
-
"`within_apply(compute=..., action=...)` to "
|
196
|
-
"`within_apply(within=..., apply=...)` or `within_apply(..., ...)`.",
|
197
|
-
category=DeprecationWarning,
|
198
|
-
stacklevel=2,
|
199
|
-
)
|
200
|
-
if compute is not None:
|
201
|
-
within = compute
|
202
|
-
if action is not None:
|
203
|
-
apply = action
|
204
|
-
if TYPE_CHECKING:
|
205
|
-
assert within is not None
|
206
|
-
assert apply is not None
|
207
144
|
_validate_operand(within)
|
208
145
|
_validate_operand(apply)
|
209
146
|
assert QCallable.CURRENT_EXPANDABLE is not None
|
210
147
|
source_ref = get_source_ref(sys._getframe(1))
|
211
|
-
|
212
|
-
|
213
|
-
|
214
|
-
|
215
|
-
source_ref=source_ref,
|
216
|
-
)
|
148
|
+
within_apply_stmt = WithinApply(
|
149
|
+
compute=_operand_to_body(within, "within"),
|
150
|
+
action=_operand_to_body(apply, "apply"),
|
151
|
+
source_ref=source_ref,
|
217
152
|
)
|
153
|
+
within_apply_stmt.set_generative_block("within", within)
|
154
|
+
within_apply_stmt.set_generative_block("apply", apply)
|
155
|
+
QCallable.CURRENT_EXPANDABLE.append_statement_to_body(within_apply_stmt)
|
218
156
|
|
219
157
|
|
220
158
|
def repeat(count: Union[SymbolicExpr, int], iteration: Callable[[int], None]) -> None:
|
@@ -237,99 +175,41 @@ def repeat(count: Union[SymbolicExpr, int], iteration: Callable[[int], None]) ->
|
|
237
175
|
"Argument 'iteration' to 'repeat' should be a callable that takes one integer argument."
|
238
176
|
)
|
239
177
|
|
240
|
-
|
241
|
-
|
242
|
-
|
243
|
-
|
244
|
-
|
245
|
-
source_ref=source_ref,
|
246
|
-
)
|
178
|
+
repeat_stmt = Repeat(
|
179
|
+
iter_var=inspect.getfullargspec(iteration).args[0],
|
180
|
+
count=Expression(expr=str(count)),
|
181
|
+
body=iteration_operand.body,
|
182
|
+
source_ref=source_ref,
|
247
183
|
)
|
184
|
+
repeat_stmt.set_generative_block("body", iteration)
|
185
|
+
QCallable.CURRENT_EXPANDABLE.append_statement_to_body(repeat_stmt)
|
248
186
|
|
249
187
|
|
250
|
-
@overload # FIXME: Remove overloading (CAD-21932)
|
251
188
|
def power(
|
252
|
-
exponent: SymbolicExpr,
|
189
|
+
exponent: Union[SymbolicExpr, int],
|
253
190
|
stmt_block: Union[QCallable, Callable[[], None]],
|
254
191
|
) -> None:
|
255
|
-
pass
|
256
|
-
|
257
|
-
|
258
|
-
@overload
|
259
|
-
def power(
|
260
|
-
exponent: int,
|
261
|
-
stmt_block: Union[QCallable, Callable[[], None]],
|
262
|
-
) -> None:
|
263
|
-
pass
|
264
|
-
|
265
|
-
|
266
|
-
def power(
|
267
|
-
exponent: Optional[Union[SymbolicExpr, int]] = None,
|
268
|
-
stmt_block: Optional[Union[QCallable, Callable[[], None]]] = None,
|
269
|
-
power: Optional[Union[SymbolicExpr, int]] = None,
|
270
|
-
operand: Optional[Union[QCallable, Callable[[], None]]] = None,
|
271
|
-
) -> None:
|
272
|
-
if power is not None or operand is not None:
|
273
|
-
warnings.warn(
|
274
|
-
"Parameters 'exponent' and 'operand' of function 'power' have been "
|
275
|
-
"renamed to 'exponent' and 'stmt_block' respectively. Parameters "
|
276
|
-
"'exponent' and 'operand' will be deprecated in a future release.\nHint: "
|
277
|
-
"Change `power(power=..., operand=...)` to "
|
278
|
-
"`power(exponent=..., stmt_block=...)` or `power(..., ...)`.",
|
279
|
-
category=DeprecationWarning,
|
280
|
-
stacklevel=2,
|
281
|
-
)
|
282
|
-
if power is not None:
|
283
|
-
exponent = power
|
284
|
-
if operand is not None:
|
285
|
-
stmt_block = operand
|
286
|
-
if TYPE_CHECKING:
|
287
|
-
assert exponent is not None
|
288
|
-
assert stmt_block is not None
|
289
192
|
_validate_operand(stmt_block)
|
290
193
|
assert QCallable.CURRENT_EXPANDABLE is not None
|
291
194
|
source_ref = get_source_ref(sys._getframe(1))
|
292
|
-
|
293
|
-
|
294
|
-
|
295
|
-
|
296
|
-
source_ref=source_ref,
|
297
|
-
)
|
195
|
+
power_stmt = Power(
|
196
|
+
power=Expression(expr=str(exponent)),
|
197
|
+
body=_operand_to_body(stmt_block, "stmt_block"),
|
198
|
+
source_ref=source_ref,
|
298
199
|
)
|
200
|
+
power_stmt.set_generative_block("body", stmt_block)
|
201
|
+
QCallable.CURRENT_EXPANDABLE.append_statement_to_body(power_stmt)
|
299
202
|
|
300
203
|
|
301
|
-
|
302
|
-
def invert(stmt_block: QCallable) -> None:
|
303
|
-
pass
|
304
|
-
|
305
|
-
|
306
|
-
@overload
|
307
|
-
def invert(stmt_block: Callable[[], None]) -> None:
|
308
|
-
pass
|
309
|
-
|
310
|
-
|
311
|
-
def invert(
|
312
|
-
stmt_block: Optional[Union[QCallable, Callable[[], None]]] = None,
|
313
|
-
operand: Optional[Union[QCallable, Callable[[], None]]] = None,
|
314
|
-
) -> None:
|
315
|
-
if operand is not None:
|
316
|
-
warnings.warn(
|
317
|
-
"Parameter 'operand' of function 'invert' has been renamed to "
|
318
|
-
"'stmt_block'. Parameter 'operand' will be deprecated in a future "
|
319
|
-
"release.\nHint: Change `invert(operand=...)` to `invert(stmt_block=...)` "
|
320
|
-
"or `invert(...)`.",
|
321
|
-
category=DeprecationWarning,
|
322
|
-
stacklevel=2,
|
323
|
-
)
|
324
|
-
stmt_block = operand
|
325
|
-
if TYPE_CHECKING:
|
326
|
-
assert stmt_block is not None
|
204
|
+
def invert(stmt_block: Union[QCallable, Callable[[], None]]) -> None:
|
327
205
|
_validate_operand(stmt_block)
|
328
206
|
assert QCallable.CURRENT_EXPANDABLE is not None
|
329
207
|
source_ref = get_source_ref(sys._getframe(1))
|
330
|
-
|
331
|
-
|
208
|
+
invert_stmt = Invert(
|
209
|
+
body=_operand_to_body(stmt_block, "stmt_block"), source_ref=source_ref
|
332
210
|
)
|
211
|
+
invert_stmt.set_generative_block("body", stmt_block)
|
212
|
+
QCallable.CURRENT_EXPANDABLE.append_statement_to_body(invert_stmt)
|
333
213
|
|
334
214
|
|
335
215
|
def phase(expr: SymbolicExpr, theta: float = 1.0) -> None:
|
@@ -174,7 +174,7 @@ def _interpret_generative_model(
|
|
174
174
|
gen_model,
|
175
175
|
{gen_func.func_decl.name: gen_func.func_decl for gen_func in gen_functions},
|
176
176
|
)
|
177
|
-
interpreter = Interpreter(gen_model, gen_functions)
|
177
|
+
interpreter = Interpreter(gen_model, gen_functions, is_frontend=True)
|
178
178
|
set_frontend_interpreter(interpreter)
|
179
179
|
functions_dict = nameables_to_dict(interpreter.expand().functions)
|
180
180
|
|
classiq/qmod/generative.py
CHANGED
@@ -1,7 +1,8 @@
|
|
1
1
|
from contextlib import contextmanager
|
2
|
-
from typing import TYPE_CHECKING, Iterator, Optional
|
2
|
+
from typing import TYPE_CHECKING, Any, Iterator, Optional
|
3
3
|
|
4
4
|
from classiq.interface.exceptions import ClassiqError
|
5
|
+
from classiq.interface.generator.expressions.expression import Expression
|
5
6
|
|
6
7
|
if TYPE_CHECKING:
|
7
8
|
from classiq.model_expansions.interpreter import Interpreter
|
@@ -20,8 +21,10 @@ def generative_mode_context(generative: bool) -> Iterator[None]:
|
|
20
21
|
global _GENERATIVE_MODE
|
21
22
|
previous = _GENERATIVE_MODE
|
22
23
|
_GENERATIVE_MODE = generative
|
23
|
-
|
24
|
-
|
24
|
+
try:
|
25
|
+
yield
|
26
|
+
finally:
|
27
|
+
_GENERATIVE_MODE = previous
|
25
28
|
|
26
29
|
|
27
30
|
@contextmanager
|
@@ -29,8 +32,10 @@ def enable_generative_expansion(enabled: bool) -> Iterator[None]:
|
|
29
32
|
global _GENERATIVE_ENABLED_SWITCH
|
30
33
|
previous = _GENERATIVE_ENABLED_SWITCH
|
31
34
|
_GENERATIVE_ENABLED_SWITCH = enabled
|
32
|
-
|
33
|
-
|
35
|
+
try:
|
36
|
+
yield
|
37
|
+
finally:
|
38
|
+
_GENERATIVE_ENABLED_SWITCH = previous
|
34
39
|
|
35
40
|
|
36
41
|
def is_generative_expansion_enabled() -> bool:
|
@@ -46,3 +51,7 @@ def get_frontend_interpreter() -> "Interpreter":
|
|
46
51
|
if _FRONTEND_INTERPRETER is None:
|
47
52
|
raise ClassiqError("Interpreter was not set")
|
48
53
|
return _FRONTEND_INTERPRETER
|
54
|
+
|
55
|
+
|
56
|
+
def interpret_expression(expr: str) -> Any:
|
57
|
+
return get_frontend_interpreter().evaluate(Expression(expr=expr)).value
|
@@ -47,6 +47,7 @@ from classiq.interface.model.quantum_expressions.amplitude_loading_operation imp
|
|
47
47
|
)
|
48
48
|
from classiq.interface.model.quantum_expressions.arithmetic_operation import (
|
49
49
|
ArithmeticOperation,
|
50
|
+
ArithmeticOperationKind,
|
50
51
|
)
|
51
52
|
from classiq.interface.model.quantum_function_call import (
|
52
53
|
OperandIdentifier,
|
@@ -186,13 +187,11 @@ class DSLPrettyPrinter(Visitor):
|
|
186
187
|
def visit_QuantumNumeric(self, qtype: QuantumNumeric) -> str:
|
187
188
|
params = ""
|
188
189
|
if qtype.size is not None:
|
189
|
-
assert qtype.is_signed is not None
|
190
|
-
assert qtype.fraction_digits is not None
|
191
|
-
|
192
190
|
params = "<{}>".format(
|
193
191
|
", ".join(
|
194
192
|
self.visit(param)
|
195
193
|
for param in [qtype.size, qtype.is_signed, qtype.fraction_digits]
|
194
|
+
if param is not None
|
196
195
|
)
|
197
196
|
)
|
198
197
|
|
@@ -258,7 +257,7 @@ class DSLPrettyPrinter(Visitor):
|
|
258
257
|
|
259
258
|
def visit_PhaseOperation(self, op: PhaseOperation) -> str:
|
260
259
|
theta = f", {self.visit(op.theta)}" if op.theta else ""
|
261
|
-
phase = f"{self._indent}phase ({self.visit(op.expression)}{theta})
|
260
|
+
phase = f"{self._indent}phase ({self.visit(op.expression)}{theta});\n"
|
262
261
|
return phase
|
263
262
|
|
264
263
|
def visit_ClassicalIf(self, op: ClassicalIf) -> str:
|
@@ -346,7 +345,12 @@ class DSLPrettyPrinter(Visitor):
|
|
346
345
|
return f"{self.visit(var_ref.base_handle)}.{self.visit(var_ref.field)}"
|
347
346
|
|
348
347
|
def visit_ArithmeticOperation(self, arith_op: ArithmeticOperation) -> str:
|
349
|
-
|
348
|
+
if arith_op.get_operation_kind() == ArithmeticOperationKind.Assignment:
|
349
|
+
op = "="
|
350
|
+
elif arith_op.get_operation_kind() == ArithmeticOperationKind.InplaceXor:
|
351
|
+
op = "^="
|
352
|
+
else:
|
353
|
+
op = "+="
|
350
354
|
return f"{self._indent}{self.visit(arith_op.result_var)} {op} {self.visit(arith_op.expression)};\n"
|
351
355
|
|
352
356
|
def visit_AmplitudeLoadingOperation(
|
@@ -47,6 +47,7 @@ from classiq.interface.model.quantum_expressions.amplitude_loading_operation imp
|
|
47
47
|
)
|
48
48
|
from classiq.interface.model.quantum_expressions.arithmetic_operation import (
|
49
49
|
ArithmeticOperation,
|
50
|
+
ArithmeticOperationKind,
|
50
51
|
)
|
51
52
|
from classiq.interface.model.quantum_expressions.quantum_expression import (
|
52
53
|
QuantumAssignmentOperation,
|
@@ -115,12 +116,10 @@ class VariableDeclarationAssignment(Visitor):
|
|
115
116
|
|
116
117
|
params = []
|
117
118
|
if qtype.size is not None:
|
118
|
-
assert qtype.is_signed is not None
|
119
|
-
assert qtype.fraction_digits is not None
|
120
|
-
|
121
119
|
params = [
|
122
120
|
self.pretty_printer.visit(param)
|
123
121
|
for param in [qtype.size, qtype.is_signed, qtype.fraction_digits]
|
122
|
+
if param is not None
|
124
123
|
]
|
125
124
|
|
126
125
|
return "QNum", params
|
@@ -470,7 +469,12 @@ class PythonPrettyPrinter(Visitor):
|
|
470
469
|
return f"{self.visit(var_ref.base_handle)}.{self.visit(var_ref.field)}"
|
471
470
|
|
472
471
|
def visit_ArithmeticOperation(self, arith_op: ArithmeticOperation) -> str:
|
473
|
-
|
472
|
+
if arith_op.get_operation_kind() == ArithmeticOperationKind.Assignment:
|
473
|
+
op = "|="
|
474
|
+
elif arith_op.get_operation_kind() == ArithmeticOperationKind.InplaceXor:
|
475
|
+
op = "^="
|
476
|
+
else:
|
477
|
+
op = "+="
|
474
478
|
return f"{self._indent}{self.visit(arith_op.result_var)} {op} {self.visit(arith_op.expression)}\n"
|
475
479
|
|
476
480
|
def visit_AmplitudeLoadingOperation(
|