classiq 0.87.0__py3-none-any.whl → 0.88.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.
Potentially problematic release.
This version of classiq might be problematic. Click here for more details.
- classiq/applications/__init__.py +1 -2
- classiq/applications/combinatorial_helpers/combinatorial_problem_utils.py +1 -1
- classiq/applications/hamiltonian/pauli_decomposition.py +1 -1
- classiq/evaluators/qmod_annotated_expression.py +30 -7
- classiq/evaluators/qmod_expression_visitors/qmod_expression_bwc.py +0 -5
- classiq/evaluators/qmod_expression_visitors/qmod_expression_evaluator.py +18 -11
- classiq/evaluators/qmod_expression_visitors/qmod_expression_renamer.py +14 -7
- classiq/evaluators/qmod_expression_visitors/qmod_expression_simplifier.py +39 -16
- classiq/evaluators/qmod_node_evaluators/attribute_evaluation.py +1 -1
- classiq/evaluators/qmod_node_evaluators/classical_function_evaluation.py +18 -8
- classiq/evaluators/qmod_node_evaluators/compare_evaluation.py +8 -0
- classiq/evaluators/qmod_node_evaluators/constant_evaluation.py +4 -1
- classiq/evaluators/qmod_node_evaluators/numeric_attrs_utils.py +1 -1
- classiq/evaluators/qmod_node_evaluators/struct_instantiation_evaluation.py +1 -1
- classiq/evaluators/qmod_node_evaluators/subscript_evaluation.py +3 -3
- classiq/evaluators/qmod_node_evaluators/utils.py +1 -1
- classiq/evaluators/qmod_type_inference/classical_type_inference.py +4 -4
- classiq/evaluators/qmod_type_inference/quantum_type_inference.py +38 -0
- classiq/evaluators/type_type_match.py +1 -1
- classiq/execution/execution_session.py +17 -2
- classiq/interface/_version.py +1 -1
- classiq/interface/execution/primitives.py +1 -0
- classiq/interface/generator/application_apis/__init__.py +0 -1
- classiq/interface/generator/expressions/atomic_expression_functions.py +0 -2
- classiq/interface/generator/function_param_list.py +0 -4
- classiq/interface/generator/functions/classical_type.py +8 -0
- classiq/interface/generator/functions/type_name.py +6 -0
- classiq/interface/generator/transpiler_basis_gates.py +5 -1
- classiq/interface/generator/types/builtin_enum_declarations.py +0 -8
- classiq/interface/model/classical_if.py +16 -8
- classiq/interface/model/classical_parameter_declaration.py +4 -0
- classiq/interface/model/port_declaration.py +12 -0
- classiq/interface/model/quantum_function_declaration.py +12 -0
- classiq/interface/model/quantum_type.py +56 -0
- classiq/interface/pretty_print/expression_to_qmod.py +3 -17
- classiq/model_expansions/quantum_operations/allocate.py +1 -1
- classiq/model_expansions/quantum_operations/handle_evaluator.py +2 -8
- classiq/open_library/functions/__init__.py +1 -0
- classiq/open_library/functions/lcu.py +2 -2
- classiq/open_library/functions/state_preparation.py +47 -5
- classiq/qmod/builtins/__init__.py +0 -3
- classiq/qmod/builtins/classical_functions.py +0 -28
- classiq/qmod/builtins/enums.py +24 -18
- classiq/qmod/builtins/functions/__init__.py +0 -5
- classiq/qmod/builtins/operations.py +142 -0
- classiq/qmod/builtins/structs.py +0 -11
- classiq/qmod/native/pretty_printer.py +1 -1
- classiq/qmod/pretty_print/expression_to_python.py +3 -6
- classiq/qmod/pretty_print/pretty_printer.py +4 -1
- classiq/qmod/qmod_variable.py +94 -2
- classiq/qmod/semantics/annotation/call_annotation.py +4 -2
- classiq/qmod/semantics/annotation/qstruct_annotator.py +20 -5
- {classiq-0.87.0.dist-info → classiq-0.88.0.dist-info}/METADATA +3 -3
- {classiq-0.87.0.dist-info → classiq-0.88.0.dist-info}/RECORD +55 -67
- classiq/applications/finance/__init__.py +0 -15
- classiq/interface/finance/__init__.py +0 -0
- classiq/interface/finance/finance_modelling_params.py +0 -11
- classiq/interface/finance/function_input.py +0 -102
- classiq/interface/finance/gaussian_model_input.py +0 -50
- classiq/interface/finance/log_normal_model_input.py +0 -40
- classiq/interface/finance/model_input.py +0 -22
- classiq/interface/generator/application_apis/finance_declarations.py +0 -108
- classiq/interface/generator/expressions/enums/__init__.py +0 -0
- classiq/interface/generator/expressions/enums/finance_functions.py +0 -12
- classiq/interface/generator/finance.py +0 -107
- classiq/qmod/builtins/functions/finance.py +0 -34
- {classiq-0.87.0.dist-info → classiq-0.88.0.dist-info}/WHEEL +0 -0
classiq/applications/__init__.py
CHANGED
|
@@ -43,7 +43,7 @@ def compute_qaoa_initial_point(
|
|
|
43
43
|
|
|
44
44
|
beta_params: np.ndarray = np.linspace(1, 0, repetitions) * time_step
|
|
45
45
|
gamma_params: np.ndarray = np.linspace(0, 1, repetitions) * time_step
|
|
46
|
-
return
|
|
46
|
+
return [float(x) for x in itertools.chain(*zip(gamma_params, beta_params))]
|
|
47
47
|
|
|
48
48
|
|
|
49
49
|
def pyo_model_to_hamiltonian(
|
|
@@ -137,7 +137,7 @@ def hamiltonian_to_matrix(
|
|
|
137
137
|
hamiltonian = _sparse_pauli_to_list(hamiltonian)
|
|
138
138
|
matrix = np.zeros(
|
|
139
139
|
[2 ** len(hamiltonian[0].pauli), 2 ** len(hamiltonian[0].pauli)],
|
|
140
|
-
dtype=np.
|
|
140
|
+
dtype=np.complex128,
|
|
141
141
|
)
|
|
142
142
|
for p in hamiltonian:
|
|
143
143
|
matrix += p.coefficient * pauli_string_to_mat(p.pauli)
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import ast
|
|
2
|
-
from collections.abc import Sequence
|
|
2
|
+
from collections.abc import Mapping, Sequence
|
|
3
3
|
from dataclasses import dataclass
|
|
4
4
|
from enum import Enum
|
|
5
5
|
from typing import Any, Union, cast
|
|
@@ -45,7 +45,7 @@ def qmod_val_to_str(val: Any) -> str:
|
|
|
45
45
|
f"{field_name}={qmod_val_to_str(field_val)}"
|
|
46
46
|
for field_name, field_val in val.fields.items()
|
|
47
47
|
)
|
|
48
|
-
return f"{val.struct_declaration.name}
|
|
48
|
+
return f"struct_literal({val.struct_declaration.name}, {fields})"
|
|
49
49
|
if isinstance(val, list):
|
|
50
50
|
return f"[{', '.join(qmod_val_to_str(item) for item in val)}]"
|
|
51
51
|
if isinstance(val, Enum):
|
|
@@ -82,6 +82,7 @@ class QmodAnnotatedExpression:
|
|
|
82
82
|
QmodExprNodeId, QuantumTypeAttributeAnnotation
|
|
83
83
|
] = {}
|
|
84
84
|
self._concatenations: dict[QmodExprNodeId, ConcatenationAnnotation] = {}
|
|
85
|
+
self._locked = False
|
|
85
86
|
|
|
86
87
|
def __str__(self) -> str:
|
|
87
88
|
return ast.unparse(_ExprInliner(self).visit(self.root))
|
|
@@ -93,6 +94,8 @@ class QmodAnnotatedExpression:
|
|
|
93
94
|
return self._node_mapping[node_id]
|
|
94
95
|
|
|
95
96
|
def set_value(self, node: Union[ast.AST, QmodExprNodeId], value: Any) -> None:
|
|
97
|
+
if self._locked:
|
|
98
|
+
raise ClassiqInternalExpansionError("QAE is locked")
|
|
96
99
|
if isinstance(node, ast.AST):
|
|
97
100
|
node = id(node)
|
|
98
101
|
self._values[node] = value
|
|
@@ -110,6 +113,8 @@ class QmodAnnotatedExpression:
|
|
|
110
113
|
def set_type(
|
|
111
114
|
self, node: Union[ast.AST, QmodExprNodeId], qmod_type: QmodType
|
|
112
115
|
) -> None:
|
|
116
|
+
if self._locked:
|
|
117
|
+
raise ClassiqInternalExpansionError("QAE is locked")
|
|
113
118
|
if isinstance(node, ast.AST):
|
|
114
119
|
node_id = id(node)
|
|
115
120
|
self._node_mapping[node_id] = node
|
|
@@ -138,6 +143,8 @@ class QmodAnnotatedExpression:
|
|
|
138
143
|
return cast(ClassicalType, qmod_type)
|
|
139
144
|
|
|
140
145
|
def set_var(self, node: Union[ast.AST, QmodExprNodeId], var: HandleBinding) -> None:
|
|
146
|
+
if self._locked:
|
|
147
|
+
raise ClassiqInternalExpansionError("QAE is locked")
|
|
141
148
|
var = var.collapse()
|
|
142
149
|
if isinstance(node, ast.AST):
|
|
143
150
|
node = id(node)
|
|
@@ -165,6 +172,8 @@ class QmodAnnotatedExpression:
|
|
|
165
172
|
return node in self._quantum_vars
|
|
166
173
|
|
|
167
174
|
def remove_var(self, node: Union[ast.AST, QmodExprNodeId]) -> None:
|
|
175
|
+
if self._locked:
|
|
176
|
+
raise ClassiqInternalExpansionError("QAE is locked")
|
|
168
177
|
if isinstance(node, ast.AST):
|
|
169
178
|
node = id(node)
|
|
170
179
|
if node in self._classical_vars:
|
|
@@ -178,6 +187,8 @@ class QmodAnnotatedExpression:
|
|
|
178
187
|
value: Union[ast.AST, QmodExprNodeId],
|
|
179
188
|
index: Union[ast.AST, QmodExprNodeId],
|
|
180
189
|
) -> None:
|
|
190
|
+
if self._locked:
|
|
191
|
+
raise ClassiqInternalExpansionError("QAE is locked")
|
|
181
192
|
if isinstance(node, ast.AST):
|
|
182
193
|
node = id(node)
|
|
183
194
|
if isinstance(value, ast.AST):
|
|
@@ -195,7 +206,7 @@ class QmodAnnotatedExpression:
|
|
|
195
206
|
|
|
196
207
|
def get_quantum_subscripts(
|
|
197
208
|
self,
|
|
198
|
-
) ->
|
|
209
|
+
) -> Mapping[QmodExprNodeId, QuantumSubscriptAnnotation]:
|
|
199
210
|
return self._quantum_subscripts
|
|
200
211
|
|
|
201
212
|
def set_quantum_type_attr(
|
|
@@ -204,6 +215,8 @@ class QmodAnnotatedExpression:
|
|
|
204
215
|
value: Union[ast.AST, QmodExprNodeId],
|
|
205
216
|
attr: str,
|
|
206
217
|
) -> None:
|
|
218
|
+
if self._locked:
|
|
219
|
+
raise ClassiqInternalExpansionError("QAE is locked")
|
|
207
220
|
if isinstance(node, ast.AST):
|
|
208
221
|
node = id(node)
|
|
209
222
|
if isinstance(value, ast.AST):
|
|
@@ -219,7 +232,7 @@ class QmodAnnotatedExpression:
|
|
|
219
232
|
|
|
220
233
|
def get_quantum_type_attributes(
|
|
221
234
|
self,
|
|
222
|
-
) ->
|
|
235
|
+
) -> Mapping[QmodExprNodeId, QuantumTypeAttributeAnnotation]:
|
|
223
236
|
return self._quantum_type_attrs
|
|
224
237
|
|
|
225
238
|
def set_concatenation(
|
|
@@ -227,6 +240,8 @@ class QmodAnnotatedExpression:
|
|
|
227
240
|
node: Union[ast.AST, QmodExprNodeId],
|
|
228
241
|
elements: Sequence[Union[ast.AST, QmodExprNodeId]],
|
|
229
242
|
) -> None:
|
|
243
|
+
if self._locked:
|
|
244
|
+
raise ClassiqInternalExpansionError("QAE is locked")
|
|
230
245
|
if isinstance(node, ast.AST):
|
|
231
246
|
node = id(node)
|
|
232
247
|
inlined_elements: list[QmodExprNodeId] = []
|
|
@@ -244,13 +259,13 @@ class QmodAnnotatedExpression:
|
|
|
244
259
|
node = id(node)
|
|
245
260
|
return node in self._concatenations
|
|
246
261
|
|
|
247
|
-
def get_concatenations(self) ->
|
|
262
|
+
def get_concatenations(self) -> Mapping[QmodExprNodeId, ConcatenationAnnotation]:
|
|
248
263
|
return self._concatenations
|
|
249
264
|
|
|
250
|
-
def get_classical_vars(self) ->
|
|
265
|
+
def get_classical_vars(self) -> Mapping[QmodExprNodeId, HandleBinding]:
|
|
251
266
|
return self._classical_vars
|
|
252
267
|
|
|
253
|
-
def get_quantum_vars(self) ->
|
|
268
|
+
def get_quantum_vars(self) -> Mapping[QmodExprNodeId, HandleBinding]:
|
|
254
269
|
return self._quantum_vars
|
|
255
270
|
|
|
256
271
|
def clear_node_data(self, node: Union[ast.AST, QmodExprNodeId]) -> None:
|
|
@@ -282,3 +297,11 @@ class QmodAnnotatedExpression:
|
|
|
282
297
|
self._quantum_subscripts |= other._quantum_subscripts
|
|
283
298
|
self._quantum_type_attrs |= other._quantum_type_attrs
|
|
284
299
|
self._concatenations |= other._concatenations
|
|
300
|
+
|
|
301
|
+
def clone(self) -> "QmodAnnotatedExpression":
|
|
302
|
+
expr_val = QmodAnnotatedExpression(self.root)
|
|
303
|
+
expr_val._add_data_from(self)
|
|
304
|
+
return expr_val
|
|
305
|
+
|
|
306
|
+
def lock(self) -> None:
|
|
307
|
+
self._locked = True
|
|
@@ -73,11 +73,6 @@ class QmodExpressionBwc(ast.NodeTransformer):
|
|
|
73
73
|
return node
|
|
74
74
|
return ast.Compare(left=args[0], ops=[ast.GtE()], comparators=[args[1]])
|
|
75
75
|
|
|
76
|
-
if func == "struct_literal":
|
|
77
|
-
if num_args != 1:
|
|
78
|
-
return node
|
|
79
|
-
return ast.Call(func=node.args[0], args=[], keywords=node.keywords)
|
|
80
|
-
|
|
81
76
|
if func == "do_subscript":
|
|
82
77
|
if num_args != 2 or num_kwargs != 0:
|
|
83
78
|
return node
|
|
@@ -103,8 +103,8 @@ class QmodExpressionEvaluator(ast.NodeVisitor):
|
|
|
103
103
|
|
|
104
104
|
def visit(self, node: ast.AST) -> None:
|
|
105
105
|
if not isinstance(node, _SUPPORTED_NODES):
|
|
106
|
-
raise
|
|
107
|
-
f"Syntax error: {type(node).__name__!r} is not
|
|
106
|
+
raise ClassiqExpansionError(
|
|
107
|
+
f"Syntax error: {type(node).__name__!r} is not a valid Qmod expression"
|
|
108
108
|
)
|
|
109
109
|
super().visit(node)
|
|
110
110
|
|
|
@@ -138,11 +138,23 @@ class QmodExpressionEvaluator(ast.NodeVisitor):
|
|
|
138
138
|
self._eval_piecewise(node)
|
|
139
139
|
return
|
|
140
140
|
|
|
141
|
-
for arg in node.args:
|
|
142
|
-
self.visit(arg)
|
|
143
141
|
for kwarg in node.keywords:
|
|
144
142
|
self.visit(kwarg)
|
|
145
143
|
|
|
144
|
+
if (
|
|
145
|
+
func_name == "struct_literal"
|
|
146
|
+
and len(node.args) == 1
|
|
147
|
+
and isinstance(node.args[0], ast.Name)
|
|
148
|
+
and (struct_name := node.args[0].id) in self._classical_struct_decls
|
|
149
|
+
):
|
|
150
|
+
eval_struct_instantiation(
|
|
151
|
+
self._expr_val, node, self._classical_struct_decls[struct_name]
|
|
152
|
+
)
|
|
153
|
+
return
|
|
154
|
+
|
|
155
|
+
for arg in node.args:
|
|
156
|
+
self.visit(arg)
|
|
157
|
+
|
|
146
158
|
if func_name == "measure":
|
|
147
159
|
eval_measurement(self._expr_val, node)
|
|
148
160
|
return
|
|
@@ -157,13 +169,6 @@ class QmodExpressionEvaluator(ast.NodeVisitor):
|
|
|
157
169
|
)
|
|
158
170
|
return
|
|
159
171
|
|
|
160
|
-
# FIXME: Remove (CLS-3241)
|
|
161
|
-
if func_name in self._classical_struct_decls:
|
|
162
|
-
eval_struct_instantiation(
|
|
163
|
-
self._expr_val, node, self._classical_struct_decls[func_name]
|
|
164
|
-
)
|
|
165
|
-
return
|
|
166
|
-
|
|
167
172
|
# FIXME: Remove (CLS-3241)
|
|
168
173
|
if func_name in self._classical_function_callables:
|
|
169
174
|
if func_name not in self._classical_function_declarations:
|
|
@@ -176,6 +181,7 @@ class QmodExpressionEvaluator(ast.NodeVisitor):
|
|
|
176
181
|
)
|
|
177
182
|
return
|
|
178
183
|
|
|
184
|
+
# FIXME: Remove (CLS-3241)
|
|
179
185
|
if func_name in self._classical_function_declarations:
|
|
180
186
|
eval_symbolic_function(
|
|
181
187
|
self._expr_val, node, self._classical_function_declarations[func_name]
|
|
@@ -272,4 +278,5 @@ def evaluate_qmod_expression(
|
|
|
272
278
|
classical_function_callables=classical_function_callables,
|
|
273
279
|
scope=scope,
|
|
274
280
|
).visit(expr_value.root)
|
|
281
|
+
expr_value.lock()
|
|
275
282
|
return expr_value
|
|
@@ -9,10 +9,12 @@ from classiq.evaluators.qmod_annotated_expression import (
|
|
|
9
9
|
def replace_expression_vars(
|
|
10
10
|
expr_val: QmodAnnotatedExpression,
|
|
11
11
|
renaming: dict[HandleBinding, HandleBinding],
|
|
12
|
-
) ->
|
|
12
|
+
) -> QmodAnnotatedExpression:
|
|
13
|
+
expr_val = expr_val.clone()
|
|
13
14
|
if len(renaming) == 0:
|
|
14
|
-
|
|
15
|
-
|
|
15
|
+
expr_val.lock()
|
|
16
|
+
return expr_val
|
|
17
|
+
all_vars = dict(expr_val.get_classical_vars()) | dict(expr_val.get_quantum_vars())
|
|
16
18
|
for node_id, var in all_vars.items():
|
|
17
19
|
renamed_var = var
|
|
18
20
|
for source, target in renaming.items():
|
|
@@ -24,15 +26,18 @@ def replace_expression_vars(
|
|
|
24
26
|
expr_val.clear_node_data(node_id)
|
|
25
27
|
expr_val.set_type(node_id, node_type)
|
|
26
28
|
expr_val.set_var(node_id, renamed_var)
|
|
27
|
-
|
|
29
|
+
expr_val.lock()
|
|
30
|
+
return expr_val
|
|
28
31
|
|
|
29
32
|
|
|
30
33
|
def replace_expression_type_attrs(
|
|
31
34
|
expr_val: QmodAnnotatedExpression,
|
|
32
35
|
renaming: dict[tuple[HandleBinding, str], HandleBinding],
|
|
33
|
-
) ->
|
|
36
|
+
) -> QmodAnnotatedExpression:
|
|
37
|
+
expr_val = expr_val.clone()
|
|
34
38
|
if len(renaming) == 0:
|
|
35
|
-
|
|
39
|
+
expr_val.lock()
|
|
40
|
+
return expr_val
|
|
36
41
|
type_attrs = dict(expr_val.get_quantum_type_attributes())
|
|
37
42
|
for node_id, ta in type_attrs.items():
|
|
38
43
|
var = expr_val.get_var(ta.value)
|
|
@@ -47,13 +52,15 @@ def replace_expression_type_attrs(
|
|
|
47
52
|
expr_val.clear_node_data(node_id)
|
|
48
53
|
expr_val.set_type(node_id, node_type)
|
|
49
54
|
expr_val.set_var(node_id, renamed_var)
|
|
50
|
-
|
|
55
|
+
expr_val.lock()
|
|
56
|
+
return expr_val
|
|
51
57
|
|
|
52
58
|
|
|
53
59
|
def replace_expression_nodes(
|
|
54
60
|
expr_val: QmodAnnotatedExpression,
|
|
55
61
|
renaming: dict[QmodExprNodeId, str],
|
|
56
62
|
) -> str:
|
|
63
|
+
expr_val = expr_val.clone()
|
|
57
64
|
for node_id, renamed_var in renaming.items():
|
|
58
65
|
expr_val.set_var(node_id, HandleBinding(name=f"{renamed_var}"))
|
|
59
66
|
return str(expr_val)
|
|
@@ -1,10 +1,12 @@
|
|
|
1
1
|
import ast
|
|
2
|
-
from typing import Any, cast
|
|
2
|
+
from typing import Any, Callable, TypeVar, cast
|
|
3
3
|
|
|
4
4
|
import sympy
|
|
5
5
|
|
|
6
6
|
from classiq.interface.exceptions import ClassiqInternalExpansionError
|
|
7
|
-
from classiq.interface.
|
|
7
|
+
from classiq.interface.generator.expressions.proxies.classical.qmod_struct_instance import (
|
|
8
|
+
QmodStructInstance,
|
|
9
|
+
)
|
|
8
10
|
|
|
9
11
|
from classiq.evaluators.qmod_annotated_expression import (
|
|
10
12
|
QmodAnnotatedExpression,
|
|
@@ -37,13 +39,15 @@ _SYMPY_WRAPPERS = {
|
|
|
37
39
|
do_div.__name__: do_div,
|
|
38
40
|
}
|
|
39
41
|
|
|
42
|
+
_PY_NODE = TypeVar("_PY_NODE", bound=ast.AST)
|
|
43
|
+
|
|
40
44
|
|
|
41
45
|
class _VarMaskTransformer(OutOfPlaceNodeTransformer):
|
|
42
46
|
def __init__(self, expr_val: QmodAnnotatedExpression) -> None:
|
|
43
47
|
self._expr_val = expr_val
|
|
44
48
|
self._mask_id = 0
|
|
45
49
|
self.masks: dict[str, QmodExprNodeId] = {}
|
|
46
|
-
self._assigned_masks: dict[
|
|
50
|
+
self._assigned_masks: dict[Any, str] = {}
|
|
47
51
|
|
|
48
52
|
def _create_mask(self) -> str:
|
|
49
53
|
mask = f"x{self._mask_id}"
|
|
@@ -52,27 +56,44 @@ class _VarMaskTransformer(OutOfPlaceNodeTransformer):
|
|
|
52
56
|
|
|
53
57
|
def visit(self, node: ast.AST) -> ast.AST:
|
|
54
58
|
if self._expr_val.has_value(node):
|
|
55
|
-
|
|
59
|
+
val = self._expr_val.get_value(node)
|
|
60
|
+
if not isinstance(val, (list, QmodStructInstance)):
|
|
61
|
+
return ast.Constant(value=val)
|
|
62
|
+
mask = self._create_mask()
|
|
63
|
+
self.masks[mask] = id(node)
|
|
64
|
+
return ast.Name(id=mask)
|
|
56
65
|
if self._expr_val.has_var(node):
|
|
57
66
|
var = self._expr_val.get_var(node)
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
mask = self._create_mask()
|
|
62
|
-
self._assigned_masks[var] = mask
|
|
63
|
-
self.masks[mask] = id(node)
|
|
64
|
-
return ast.Name(id=mask)
|
|
65
|
-
if self._expr_val.has_quantum_subscript(node):
|
|
67
|
+
var_str = str(var.collapse())
|
|
68
|
+
if var_str in self._assigned_masks:
|
|
69
|
+
return ast.Name(id=self._assigned_masks[var_str])
|
|
66
70
|
mask = self._create_mask()
|
|
71
|
+
self._assigned_masks[var_str] = mask
|
|
67
72
|
self.masks[mask] = id(node)
|
|
68
73
|
return ast.Name(id=mask)
|
|
69
74
|
return super().visit(node)
|
|
70
75
|
|
|
71
|
-
def
|
|
72
|
-
|
|
76
|
+
def _reduce_node(
|
|
77
|
+
self, node: _PY_NODE, inner_node: ast.AST, key: Callable[[_PY_NODE], str]
|
|
78
|
+
) -> ast.AST:
|
|
79
|
+
new_value = self.visit(inner_node)
|
|
80
|
+
if isinstance(new_value, ast.Name):
|
|
81
|
+
mask_key = (new_value.id, key(node))
|
|
82
|
+
if mask_key in self._assigned_masks:
|
|
83
|
+
return ast.Name(self._assigned_masks[mask_key])
|
|
84
|
+
mask = self._create_mask()
|
|
85
|
+
self._assigned_masks[mask_key] = mask
|
|
86
|
+
else:
|
|
87
|
+
mask = self._create_mask()
|
|
73
88
|
self.masks[mask] = id(node)
|
|
74
89
|
return ast.Name(id=mask)
|
|
75
90
|
|
|
91
|
+
def visit_Attribute(self, node: ast.Attribute) -> ast.AST:
|
|
92
|
+
return self._reduce_node(node, node.value, lambda n: n.attr)
|
|
93
|
+
|
|
94
|
+
def visit_Subscript(self, node: ast.Subscript) -> ast.AST:
|
|
95
|
+
return self._reduce_node(node, node.value, lambda n: ast.unparse(node.slice))
|
|
96
|
+
|
|
76
97
|
|
|
77
98
|
class _InverseVarMaskTransformer(OutOfPlaceNodeTransformer):
|
|
78
99
|
def __init__(
|
|
@@ -230,12 +251,14 @@ class _InverseSympyCompatibilityTransformer(OutOfPlaceNodeTransformer):
|
|
|
230
251
|
if func == BitwiseAnd.__name__:
|
|
231
252
|
return ast.BinOp(left=node.args[0], op=ast.BitAnd(), right=node.args[1])
|
|
232
253
|
|
|
233
|
-
if func == "
|
|
234
|
-
|
|
254
|
+
if func == "Abs":
|
|
255
|
+
node.func.id = "abs"
|
|
235
256
|
if func == "Max":
|
|
236
257
|
node.func.id = "max"
|
|
237
258
|
elif func == "Min":
|
|
238
259
|
node.func.id = "min"
|
|
260
|
+
if func == "Mod":
|
|
261
|
+
return ast.BinOp(left=node.args[0], op=ast.Mod(), right=node.args[1])
|
|
239
262
|
|
|
240
263
|
return node
|
|
241
264
|
|
|
@@ -42,7 +42,7 @@ def _eval_type_attribute(
|
|
|
42
42
|
return
|
|
43
43
|
if isinstance(subject_type, (ClassicalArray, QuantumBitvector)) and attr == "len":
|
|
44
44
|
expr_val.set_type(node, Integer())
|
|
45
|
-
if subject_type.
|
|
45
|
+
if subject_type.has_constant_length:
|
|
46
46
|
expr_val.set_value(node, subject_type.length_value)
|
|
47
47
|
elif isinstance(subject_type, QuantumType):
|
|
48
48
|
expr_val.set_quantum_type_attr(node, subject, attr)
|
|
@@ -30,6 +30,9 @@ from classiq.evaluators.qmod_node_evaluators.utils import (
|
|
|
30
30
|
element_types,
|
|
31
31
|
is_classical_integer,
|
|
32
32
|
)
|
|
33
|
+
from classiq.evaluators.qmod_type_inference.classical_type_inference import (
|
|
34
|
+
infer_classical_type,
|
|
35
|
+
)
|
|
33
36
|
|
|
34
37
|
# These sympy functions are not declared as int funcs for some reason...
|
|
35
38
|
INTEGER_FUNCTION_OVERRIDE = {"floor", "ceiling"}
|
|
@@ -169,7 +172,9 @@ def eval_function(
|
|
|
169
172
|
cast(str, kwarg_name): expr_val.get_value(kwarg_value)
|
|
170
173
|
for kwarg_name, kwarg_value in kwargs.items()
|
|
171
174
|
}
|
|
172
|
-
|
|
175
|
+
ret_val = func(*arg_values, **kwarg_values)
|
|
176
|
+
expr_val.set_type(node, infer_classical_type(ret_val))
|
|
177
|
+
expr_val.set_value(node, ret_val)
|
|
173
178
|
|
|
174
179
|
|
|
175
180
|
def try_eval_sympy_function(
|
|
@@ -261,10 +266,10 @@ def try_eval_builtin_function(
|
|
|
261
266
|
*[expr_val.get_value(arg) for arg in node.args]
|
|
262
267
|
)
|
|
263
268
|
ret_val: Any
|
|
264
|
-
if
|
|
265
|
-
ret_val = int(sympy_val)
|
|
266
|
-
elif isinstance(sympy_val, sympy.Expr) and sympy_val.is_imaginary:
|
|
269
|
+
if isinstance(sympy_val, sympy.Expr) and sympy_val.is_imaginary:
|
|
267
270
|
ret_val = complex(sympy_val)
|
|
271
|
+
elif args_are_int:
|
|
272
|
+
ret_val = int(sympy_val)
|
|
268
273
|
else:
|
|
269
274
|
ret_val = float(sympy_val)
|
|
270
275
|
expr_val.set_value(node, ret_val)
|
|
@@ -287,9 +292,14 @@ def try_eval_builtin_function(
|
|
|
287
292
|
_validate_no_kwargs(node)
|
|
288
293
|
expr_val.set_type(node, Real())
|
|
289
294
|
if args_have_values:
|
|
290
|
-
expr_val.
|
|
291
|
-
|
|
292
|
-
|
|
295
|
+
sympy_val = sympy.sqrt(*[expr_val.get_value(arg) for arg in node.args])
|
|
296
|
+
if isinstance(sympy_val, sympy.Expr) and sympy_val.is_imaginary:
|
|
297
|
+
ret_val = complex(sympy_val)
|
|
298
|
+
elif float(sympy_val) == int(sympy_val):
|
|
299
|
+
ret_val = int(sympy_val)
|
|
300
|
+
else:
|
|
301
|
+
ret_val = float(sympy_val)
|
|
302
|
+
expr_val.set_value(node, ret_val)
|
|
293
303
|
return True
|
|
294
304
|
|
|
295
305
|
if func_name == "abs":
|
|
@@ -301,7 +311,7 @@ def try_eval_builtin_function(
|
|
|
301
311
|
expr_val.set_type(node, ret_type)
|
|
302
312
|
if args_have_values:
|
|
303
313
|
expr_val.set_value(
|
|
304
|
-
node,
|
|
314
|
+
node, abs(*[expr_val.get_value(arg) for arg in node.args])
|
|
305
315
|
)
|
|
306
316
|
return True
|
|
307
317
|
|
|
@@ -100,12 +100,20 @@ def eval_compare(expr_val: QmodAnnotatedExpression, node: ast.Compare) -> None:
|
|
|
100
100
|
elif isinstance(op, ast.NotEq):
|
|
101
101
|
expr_val.set_value(node, left_value != right_value)
|
|
102
102
|
elif isinstance(op, ast.Lt):
|
|
103
|
+
if isinstance(left_value, complex) or isinstance(right_value, complex):
|
|
104
|
+
raise ClassiqExpansionError("Inequality with a complex number")
|
|
103
105
|
expr_val.set_value(node, left_value < right_value)
|
|
104
106
|
elif isinstance(op, ast.Gt):
|
|
107
|
+
if isinstance(left_value, complex) or isinstance(right_value, complex):
|
|
108
|
+
raise ClassiqExpansionError("Inequality with a complex number")
|
|
105
109
|
expr_val.set_value(node, left_value > right_value)
|
|
106
110
|
elif isinstance(op, ast.LtE):
|
|
111
|
+
if isinstance(left_value, complex) or isinstance(right_value, complex):
|
|
112
|
+
raise ClassiqExpansionError("Inequality with a complex number")
|
|
107
113
|
expr_val.set_value(node, left_value <= right_value)
|
|
108
114
|
elif isinstance(op, ast.GtE):
|
|
115
|
+
if isinstance(left_value, complex) or isinstance(right_value, complex):
|
|
116
|
+
raise ClassiqExpansionError("Inequality with a complex number")
|
|
109
117
|
expr_val.set_value(node, left_value >= right_value)
|
|
110
118
|
else:
|
|
111
119
|
raise ClassiqExpansionError(f"Unsupported comparison {type(op).__name__!r}")
|
|
@@ -33,7 +33,10 @@ def eval_enum_member(
|
|
|
33
33
|
}
|
|
34
34
|
attr = node.attr
|
|
35
35
|
if attr not in enum_members:
|
|
36
|
-
raise ClassiqExpansionError(
|
|
36
|
+
raise ClassiqExpansionError(
|
|
37
|
+
f"Enum {enum_name} has no member {attr!r}. Available members: "
|
|
38
|
+
f"{', '.join(enum_members.keys())}"
|
|
39
|
+
)
|
|
37
40
|
|
|
38
41
|
expr_val.set_type(node, Enum(name=enum_name))
|
|
39
42
|
expr_val.set_value(node, enum_members[attr])
|
|
@@ -20,7 +20,7 @@ from classiq.evaluators.qmod_node_evaluators.compare_evaluation import (
|
|
|
20
20
|
def eval_struct_instantiation(
|
|
21
21
|
expr_val: QmodAnnotatedExpression, node: ast.Call, decl: StructDeclaration
|
|
22
22
|
) -> None:
|
|
23
|
-
if len(node.args)
|
|
23
|
+
if len(node.args) != 1 or any(kwarg.arg is None for kwarg in node.keywords):
|
|
24
24
|
raise ClassiqExpansionError(
|
|
25
25
|
"Classical structs must be instantiated using keyword arguments"
|
|
26
26
|
)
|
|
@@ -69,7 +69,7 @@ def _eval_slice(expr_val: QmodAnnotatedExpression, node: ast.Subscript) -> None:
|
|
|
69
69
|
subject_type = expr_val.get_type(subject)
|
|
70
70
|
slice_type: QmodType
|
|
71
71
|
if isinstance(subject_type, ClassicalArray):
|
|
72
|
-
if subject_type.
|
|
72
|
+
if subject_type.has_constant_length and (
|
|
73
73
|
(start_val is not None and start_val >= subject_type.length_value)
|
|
74
74
|
or (stop_val is not None and stop_val > subject_type.length_value)
|
|
75
75
|
):
|
|
@@ -93,7 +93,7 @@ def _eval_slice(expr_val: QmodAnnotatedExpression, node: ast.Subscript) -> None:
|
|
|
93
93
|
slice_type = subject_type.get_raw_type()
|
|
94
94
|
elif isinstance(subject_type, QuantumBitvector):
|
|
95
95
|
if start_val is not None and stop_val is not None:
|
|
96
|
-
if subject_type.
|
|
96
|
+
if subject_type.has_constant_length and (
|
|
97
97
|
start_val >= subject_type.length_value
|
|
98
98
|
or stop_val > subject_type.length_value
|
|
99
99
|
):
|
|
@@ -150,7 +150,7 @@ def _eval_subscript(expr_val: QmodAnnotatedExpression, node: ast.Subscript) -> N
|
|
|
150
150
|
if isinstance(subject_type, (ClassicalArray, QuantumBitvector)):
|
|
151
151
|
if (
|
|
152
152
|
sub_val is not None
|
|
153
|
-
and subject_type.
|
|
153
|
+
and subject_type.has_constant_length
|
|
154
154
|
and sub_val >= subject_type.length_value
|
|
155
155
|
):
|
|
156
156
|
raise ClassiqExpansionError("Array index out of range")
|
|
@@ -85,7 +85,7 @@ def array_len(
|
|
|
85
85
|
) -> Optional[int]:
|
|
86
86
|
if isinstance(classical_type, ClassicalTuple):
|
|
87
87
|
return len(classical_type.element_types)
|
|
88
|
-
if classical_type.
|
|
88
|
+
if classical_type.has_constant_length:
|
|
89
89
|
return classical_type.length_value
|
|
90
90
|
return None
|
|
91
91
|
|
|
@@ -73,9 +73,9 @@ def _inject_classical_array_attributes(
|
|
|
73
73
|
if isinstance(to_type, ClassicalArray):
|
|
74
74
|
if isinstance(from_type, ClassicalArray):
|
|
75
75
|
length: Optional[Expression]
|
|
76
|
-
if from_type.
|
|
76
|
+
if from_type.has_constant_length:
|
|
77
77
|
if (
|
|
78
|
-
to_type.
|
|
78
|
+
to_type.has_constant_length
|
|
79
79
|
and from_type.length_value != to_type.length_value
|
|
80
80
|
):
|
|
81
81
|
return None
|
|
@@ -90,7 +90,7 @@ def _inject_classical_array_attributes(
|
|
|
90
90
|
return ClassicalArray(element_type=element_type, length=length)
|
|
91
91
|
if isinstance(from_type, ClassicalTuple):
|
|
92
92
|
if (
|
|
93
|
-
to_type.
|
|
93
|
+
to_type.has_constant_length
|
|
94
94
|
and len(from_type.element_types) != to_type.length_value
|
|
95
95
|
):
|
|
96
96
|
return None
|
|
@@ -103,7 +103,7 @@ def _inject_classical_array_attributes(
|
|
|
103
103
|
return ClassicalTuple(element_types=element_types)
|
|
104
104
|
return None
|
|
105
105
|
if isinstance(from_type, ClassicalArray):
|
|
106
|
-
if from_type.
|
|
106
|
+
if from_type.has_constant_length and from_type.length_value != len(
|
|
107
107
|
to_type.element_types
|
|
108
108
|
):
|
|
109
109
|
return None
|
|
@@ -290,3 +290,41 @@ def inject_quantum_type_attributes_inplace(
|
|
|
290
290
|
to_type.set_fields(updated_type.fields)
|
|
291
291
|
return True
|
|
292
292
|
raise ClassiqInternalExpansionError
|
|
293
|
+
|
|
294
|
+
|
|
295
|
+
def validate_quantum_type_attributes(quantum_type: QuantumType) -> None:
|
|
296
|
+
if isinstance(quantum_type, TypeName):
|
|
297
|
+
if len(quantum_type.fields) == 0:
|
|
298
|
+
raise ClassiqExpansionError(
|
|
299
|
+
f"QStruct {quantum_type.name} must have at least one field"
|
|
300
|
+
)
|
|
301
|
+
for field_type in quantum_type.fields.values():
|
|
302
|
+
validate_quantum_type_attributes(field_type)
|
|
303
|
+
return
|
|
304
|
+
if isinstance(quantum_type, QuantumBitvector):
|
|
305
|
+
validate_quantum_type_attributes(quantum_type.element_type)
|
|
306
|
+
if quantum_type.has_constant_length and quantum_type.length_value < 1:
|
|
307
|
+
raise ClassiqExpansionError(
|
|
308
|
+
f"QArray length must be positive, got {quantum_type.length_value}"
|
|
309
|
+
)
|
|
310
|
+
return
|
|
311
|
+
if isinstance(quantum_type, QuantumNumeric):
|
|
312
|
+
if quantum_type.has_size_in_bits and quantum_type.size_in_bits < 1:
|
|
313
|
+
raise ClassiqExpansionError(
|
|
314
|
+
f"QNum size must be positive, got {quantum_type.size_in_bits}"
|
|
315
|
+
)
|
|
316
|
+
if quantum_type.has_fraction_digits:
|
|
317
|
+
if quantum_type.fraction_digits_value < 0:
|
|
318
|
+
raise ClassiqExpansionError(
|
|
319
|
+
f"QNum fraction digits must be positive, got "
|
|
320
|
+
f"{quantum_type.fraction_digits_value}"
|
|
321
|
+
)
|
|
322
|
+
if (
|
|
323
|
+
quantum_type.has_size_in_bits
|
|
324
|
+
and quantum_type.fraction_digits_value > quantum_type.size_in_bits
|
|
325
|
+
):
|
|
326
|
+
raise ClassiqExpansionError(
|
|
327
|
+
f"QNum size ({quantum_type.size_in_bits}) must be greater or "
|
|
328
|
+
f"equals than the fraction digits "
|
|
329
|
+
f"({quantum_type.fraction_digits_value})"
|
|
330
|
+
)
|
|
@@ -21,7 +21,7 @@ def check_signature_match(
|
|
|
21
21
|
) -> None:
|
|
22
22
|
if len(decl_params) != len(op_params):
|
|
23
23
|
raise ClassiqExpansionError(
|
|
24
|
-
f"{location_str} should have {len(decl_params)} parameters, "
|
|
24
|
+
f"{location_str.capitalize()} should have {len(decl_params)} parameters, "
|
|
25
25
|
f"not {len(op_params)}"
|
|
26
26
|
)
|
|
27
27
|
for idx, (decl_param, op_param) in enumerate(zip(decl_params, op_params)):
|