classiq 0.87.0__py3-none-any.whl → 0.89.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/_internals/config.py +1 -1
- 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 +37 -15
- classiq/evaluators/qmod_expression_visitors/qmod_expression_bwc.py +0 -5
- classiq/evaluators/qmod_expression_visitors/qmod_expression_evaluator.py +20 -13
- classiq/evaluators/qmod_expression_visitors/qmod_expression_renamer.py +15 -8
- classiq/evaluators/qmod_expression_visitors/qmod_expression_simplifier.py +39 -16
- classiq/evaluators/qmod_node_evaluators/attribute_evaluation.py +67 -6
- 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/analyzer/analysis_params.py +1 -1
- classiq/interface/backend/backend_preferences.py +1 -1
- classiq/interface/execution/primitives.py +1 -0
- classiq/interface/generator/application_apis/__init__.py +0 -1
- classiq/interface/generator/arith/register_user_input.py +1 -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 +32 -3
- classiq/interface/generator/functions/function_declaration.py +0 -4
- classiq/interface/generator/functions/type_name.py +31 -0
- classiq/interface/generator/hardware_efficient_ansatz.py +1 -1
- classiq/interface/generator/quantum_function_call.py +3 -3
- classiq/interface/generator/transpiler_basis_gates.py +5 -1
- classiq/interface/generator/types/builtin_enum_declarations.py +0 -8
- classiq/interface/generator/user_defined_function_params.py +0 -3
- classiq/interface/ide/ide_data.py +1 -1
- classiq/interface/ide/visual_model.py +2 -2
- classiq/interface/model/block.py +5 -1
- classiq/interface/model/classical_if.py +16 -8
- classiq/interface/model/classical_parameter_declaration.py +4 -0
- classiq/interface/model/handle_binding.py +1 -1
- classiq/interface/model/port_declaration.py +12 -0
- classiq/interface/model/quantum_function_declaration.py +12 -0
- classiq/interface/model/quantum_lambda_function.py +1 -1
- classiq/interface/model/quantum_statement.py +2 -4
- classiq/interface/model/quantum_type.py +102 -3
- 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 +3 -0
- classiq/open_library/functions/lcu.py +2 -2
- classiq/open_library/functions/state_preparation.py +182 -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 +141 -3
- 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.89.0.dist-info}/METADATA +4 -4
- {classiq-0.87.0.dist-info → classiq-0.89.0.dist-info}/RECORD +69 -81
- 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.89.0.dist-info}/WHEEL +0 -0
classiq/_internals/config.py
CHANGED
|
@@ -24,7 +24,7 @@ class Configuration(BaseModel):
|
|
|
24
24
|
|
|
25
25
|
host: pydantic.AnyHttpUrl = pydantic.Field(..., description="Classiq backend URI.")
|
|
26
26
|
ide: pydantic.AnyHttpUrl = pydantic.Field(
|
|
27
|
-
default=DEFAULT_IDE_FE_APP, description="Classiq IDE URI."
|
|
27
|
+
default=pydantic.AnyHttpUrl(DEFAULT_IDE_FE_APP), description="Classiq IDE URI."
|
|
28
28
|
)
|
|
29
29
|
should_check_host: bool = pydantic.Field(
|
|
30
30
|
default=True, description="Should check backend URI and version."
|
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
|
|
@@ -30,7 +30,7 @@ class QuantumSubscriptAnnotation:
|
|
|
30
30
|
|
|
31
31
|
@dataclass(frozen=True)
|
|
32
32
|
class QuantumTypeAttributeAnnotation:
|
|
33
|
-
value:
|
|
33
|
+
value: HandleBinding
|
|
34
34
|
attr: str
|
|
35
35
|
|
|
36
36
|
|
|
@@ -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,9 +82,13 @@ class QmodAnnotatedExpression:
|
|
|
82
82
|
QmodExprNodeId, QuantumTypeAttributeAnnotation
|
|
83
83
|
] = {}
|
|
84
84
|
self._concatenations: dict[QmodExprNodeId, ConcatenationAnnotation] = {}
|
|
85
|
+
self._locked = False
|
|
86
|
+
|
|
87
|
+
def print_by_node(self, node: ast.AST) -> str:
|
|
88
|
+
return ast.unparse(_ExprInliner(self).visit(node))
|
|
85
89
|
|
|
86
90
|
def __str__(self) -> str:
|
|
87
|
-
return
|
|
91
|
+
return self.print_by_node(self.root)
|
|
88
92
|
|
|
89
93
|
def has_node(self, node_id: QmodExprNodeId) -> bool:
|
|
90
94
|
return node_id in self._node_mapping
|
|
@@ -93,6 +97,8 @@ class QmodAnnotatedExpression:
|
|
|
93
97
|
return self._node_mapping[node_id]
|
|
94
98
|
|
|
95
99
|
def set_value(self, node: Union[ast.AST, QmodExprNodeId], value: Any) -> None:
|
|
100
|
+
if self._locked:
|
|
101
|
+
raise ClassiqInternalExpansionError("QAE is locked")
|
|
96
102
|
if isinstance(node, ast.AST):
|
|
97
103
|
node = id(node)
|
|
98
104
|
self._values[node] = value
|
|
@@ -110,6 +116,8 @@ class QmodAnnotatedExpression:
|
|
|
110
116
|
def set_type(
|
|
111
117
|
self, node: Union[ast.AST, QmodExprNodeId], qmod_type: QmodType
|
|
112
118
|
) -> None:
|
|
119
|
+
if self._locked:
|
|
120
|
+
raise ClassiqInternalExpansionError("QAE is locked")
|
|
113
121
|
if isinstance(node, ast.AST):
|
|
114
122
|
node_id = id(node)
|
|
115
123
|
self._node_mapping[node_id] = node
|
|
@@ -138,6 +146,8 @@ class QmodAnnotatedExpression:
|
|
|
138
146
|
return cast(ClassicalType, qmod_type)
|
|
139
147
|
|
|
140
148
|
def set_var(self, node: Union[ast.AST, QmodExprNodeId], var: HandleBinding) -> None:
|
|
149
|
+
if self._locked:
|
|
150
|
+
raise ClassiqInternalExpansionError("QAE is locked")
|
|
141
151
|
var = var.collapse()
|
|
142
152
|
if isinstance(node, ast.AST):
|
|
143
153
|
node = id(node)
|
|
@@ -165,6 +175,8 @@ class QmodAnnotatedExpression:
|
|
|
165
175
|
return node in self._quantum_vars
|
|
166
176
|
|
|
167
177
|
def remove_var(self, node: Union[ast.AST, QmodExprNodeId]) -> None:
|
|
178
|
+
if self._locked:
|
|
179
|
+
raise ClassiqInternalExpansionError("QAE is locked")
|
|
168
180
|
if isinstance(node, ast.AST):
|
|
169
181
|
node = id(node)
|
|
170
182
|
if node in self._classical_vars:
|
|
@@ -178,6 +190,8 @@ class QmodAnnotatedExpression:
|
|
|
178
190
|
value: Union[ast.AST, QmodExprNodeId],
|
|
179
191
|
index: Union[ast.AST, QmodExprNodeId],
|
|
180
192
|
) -> None:
|
|
193
|
+
if self._locked:
|
|
194
|
+
raise ClassiqInternalExpansionError("QAE is locked")
|
|
181
195
|
if isinstance(node, ast.AST):
|
|
182
196
|
node = id(node)
|
|
183
197
|
if isinstance(value, ast.AST):
|
|
@@ -195,19 +209,19 @@ class QmodAnnotatedExpression:
|
|
|
195
209
|
|
|
196
210
|
def get_quantum_subscripts(
|
|
197
211
|
self,
|
|
198
|
-
) ->
|
|
212
|
+
) -> Mapping[QmodExprNodeId, QuantumSubscriptAnnotation]:
|
|
199
213
|
return self._quantum_subscripts
|
|
200
214
|
|
|
201
215
|
def set_quantum_type_attr(
|
|
202
216
|
self,
|
|
203
217
|
node: Union[ast.AST, QmodExprNodeId],
|
|
204
|
-
value:
|
|
218
|
+
value: HandleBinding,
|
|
205
219
|
attr: str,
|
|
206
220
|
) -> None:
|
|
221
|
+
if self._locked:
|
|
222
|
+
raise ClassiqInternalExpansionError("QAE is locked")
|
|
207
223
|
if isinstance(node, ast.AST):
|
|
208
224
|
node = id(node)
|
|
209
|
-
if isinstance(value, ast.AST):
|
|
210
|
-
value = id(value)
|
|
211
225
|
self._quantum_type_attrs[node] = QuantumTypeAttributeAnnotation(
|
|
212
226
|
value=value, attr=attr
|
|
213
227
|
)
|
|
@@ -219,7 +233,7 @@ class QmodAnnotatedExpression:
|
|
|
219
233
|
|
|
220
234
|
def get_quantum_type_attributes(
|
|
221
235
|
self,
|
|
222
|
-
) ->
|
|
236
|
+
) -> Mapping[QmodExprNodeId, QuantumTypeAttributeAnnotation]:
|
|
223
237
|
return self._quantum_type_attrs
|
|
224
238
|
|
|
225
239
|
def set_concatenation(
|
|
@@ -227,6 +241,8 @@ class QmodAnnotatedExpression:
|
|
|
227
241
|
node: Union[ast.AST, QmodExprNodeId],
|
|
228
242
|
elements: Sequence[Union[ast.AST, QmodExprNodeId]],
|
|
229
243
|
) -> None:
|
|
244
|
+
if self._locked:
|
|
245
|
+
raise ClassiqInternalExpansionError("QAE is locked")
|
|
230
246
|
if isinstance(node, ast.AST):
|
|
231
247
|
node = id(node)
|
|
232
248
|
inlined_elements: list[QmodExprNodeId] = []
|
|
@@ -244,13 +260,13 @@ class QmodAnnotatedExpression:
|
|
|
244
260
|
node = id(node)
|
|
245
261
|
return node in self._concatenations
|
|
246
262
|
|
|
247
|
-
def get_concatenations(self) ->
|
|
263
|
+
def get_concatenations(self) -> Mapping[QmodExprNodeId, ConcatenationAnnotation]:
|
|
248
264
|
return self._concatenations
|
|
249
265
|
|
|
250
|
-
def get_classical_vars(self) ->
|
|
266
|
+
def get_classical_vars(self) -> Mapping[QmodExprNodeId, HandleBinding]:
|
|
251
267
|
return self._classical_vars
|
|
252
268
|
|
|
253
|
-
def get_quantum_vars(self) ->
|
|
269
|
+
def get_quantum_vars(self) -> Mapping[QmodExprNodeId, HandleBinding]:
|
|
254
270
|
return self._quantum_vars
|
|
255
271
|
|
|
256
272
|
def clear_node_data(self, node: Union[ast.AST, QmodExprNodeId]) -> None:
|
|
@@ -265,9 +281,7 @@ class QmodAnnotatedExpression:
|
|
|
265
281
|
if qs is not None:
|
|
266
282
|
self.clear_node_data(qs.value)
|
|
267
283
|
self.clear_node_data(qs.index)
|
|
268
|
-
|
|
269
|
-
if qta is not None:
|
|
270
|
-
self.clear_node_data(qta.value)
|
|
284
|
+
self._quantum_type_attrs.pop(node, None)
|
|
271
285
|
cnct = self._concatenations.pop(node, None)
|
|
272
286
|
if cnct is not None:
|
|
273
287
|
for element in cnct.elements:
|
|
@@ -282,3 +296,11 @@ class QmodAnnotatedExpression:
|
|
|
282
296
|
self._quantum_subscripts |= other._quantum_subscripts
|
|
283
297
|
self._quantum_type_attrs |= other._quantum_type_attrs
|
|
284
298
|
self._concatenations |= other._concatenations
|
|
299
|
+
|
|
300
|
+
def clone(self) -> "QmodAnnotatedExpression":
|
|
301
|
+
expr_val = QmodAnnotatedExpression(self.root)
|
|
302
|
+
expr_val._add_data_from(self)
|
|
303
|
+
return expr_val
|
|
304
|
+
|
|
305
|
+
def lock(self) -> None:
|
|
306
|
+
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
|
|
@@ -85,7 +85,7 @@ class QmodExpressionEvaluator(ast.NodeVisitor):
|
|
|
85
85
|
Sequence[ClassicalFunctionDeclaration]
|
|
86
86
|
] = None,
|
|
87
87
|
classical_function_callables: Optional[Mapping[str, Callable]] = None,
|
|
88
|
-
scope: Optional[
|
|
88
|
+
scope: Optional[Mapping[str, Any]] = None,
|
|
89
89
|
) -> None:
|
|
90
90
|
self._expr_val = expr_val
|
|
91
91
|
self._treat_qnum_as_float = treat_qnum_as_float
|
|
@@ -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]
|
|
@@ -258,7 +264,7 @@ def evaluate_qmod_expression(
|
|
|
258
264
|
Sequence[ClassicalFunctionDeclaration]
|
|
259
265
|
] = None,
|
|
260
266
|
classical_function_callables: Optional[Mapping[str, Callable]] = None,
|
|
261
|
-
scope: Optional[
|
|
267
|
+
scope: Optional[Mapping[str, Any]] = None,
|
|
262
268
|
) -> QmodAnnotatedExpression:
|
|
263
269
|
expr_ast = ast.parse(expr, mode="eval").body
|
|
264
270
|
expr_value = QmodAnnotatedExpression(expr_ast)
|
|
@@ -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,18 +26,21 @@ 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
|
-
var =
|
|
43
|
+
var = ta.value
|
|
39
44
|
renamed_var = var
|
|
40
45
|
renamed_attr = ta.attr
|
|
41
46
|
for (source, attr), target in renaming.items():
|
|
@@ -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
|
|
|
@@ -5,6 +5,7 @@ from classiq.interface.exceptions import (
|
|
|
5
5
|
ClassiqExpansionError,
|
|
6
6
|
ClassiqInternalExpansionError,
|
|
7
7
|
)
|
|
8
|
+
from classiq.interface.generator.expressions.expression import Expression
|
|
8
9
|
from classiq.interface.generator.expressions.proxies.classical.qmod_struct_instance import (
|
|
9
10
|
QmodStructInstance,
|
|
10
11
|
)
|
|
@@ -15,7 +16,12 @@ from classiq.interface.generator.functions.classical_type import (
|
|
|
15
16
|
Integer,
|
|
16
17
|
)
|
|
17
18
|
from classiq.interface.generator.functions.type_name import TypeName
|
|
18
|
-
from classiq.interface.model.handle_binding import
|
|
19
|
+
from classiq.interface.model.handle_binding import (
|
|
20
|
+
FieldHandleBinding,
|
|
21
|
+
HandleBinding,
|
|
22
|
+
SlicedHandleBinding,
|
|
23
|
+
SubscriptHandleBinding,
|
|
24
|
+
)
|
|
19
25
|
from classiq.interface.model.quantum_type import (
|
|
20
26
|
QuantumBitvector,
|
|
21
27
|
QuantumNumeric,
|
|
@@ -26,6 +32,46 @@ from classiq.evaluators.qmod_annotated_expression import QmodAnnotatedExpression
|
|
|
26
32
|
from classiq.evaluators.qmod_node_evaluators.utils import QmodType
|
|
27
33
|
|
|
28
34
|
|
|
35
|
+
def _get_symbolic_quantum_var(
|
|
36
|
+
expr_val: QmodAnnotatedExpression, node: ast.AST
|
|
37
|
+
) -> HandleBinding:
|
|
38
|
+
if expr_val.has_quantum_var(node):
|
|
39
|
+
var = expr_val.get_var(node)
|
|
40
|
+
expr_val.remove_var(node)
|
|
41
|
+
return var
|
|
42
|
+
if isinstance(node, ast.Attribute):
|
|
43
|
+
return FieldHandleBinding(
|
|
44
|
+
base_handle=_get_symbolic_quantum_var(expr_val, node.value),
|
|
45
|
+
field=node.attr,
|
|
46
|
+
)
|
|
47
|
+
if isinstance(node, ast.Subscript):
|
|
48
|
+
base_var = _get_symbolic_quantum_var(expr_val, node.value)
|
|
49
|
+
slice_ = node.slice
|
|
50
|
+
if isinstance(slice_, ast.Slice):
|
|
51
|
+
if slice_.lower is None or slice_.upper is None or slice_.step is not None:
|
|
52
|
+
raise ClassiqInternalExpansionError("Illegal slice")
|
|
53
|
+
return SlicedHandleBinding(
|
|
54
|
+
base_handle=base_var,
|
|
55
|
+
start=Expression(expr=expr_val.print_by_node(slice_.lower)),
|
|
56
|
+
end=Expression(expr=expr_val.print_by_node(slice_.upper)),
|
|
57
|
+
)
|
|
58
|
+
else:
|
|
59
|
+
return SubscriptHandleBinding(
|
|
60
|
+
base_handle=base_var,
|
|
61
|
+
index=Expression(expr=expr_val.print_by_node(slice_)),
|
|
62
|
+
)
|
|
63
|
+
raise ClassiqInternalExpansionError("Symbolic variable construction failed")
|
|
64
|
+
|
|
65
|
+
|
|
66
|
+
def _remove_quantum_var(expr_val: QmodAnnotatedExpression, node: ast.AST) -> None:
|
|
67
|
+
if expr_val.has_quantum_var(node):
|
|
68
|
+
expr_val.remove_var(node)
|
|
69
|
+
elif isinstance(node, (ast.Attribute, ast.Subscript)):
|
|
70
|
+
_remove_quantum_var(expr_val, node.value)
|
|
71
|
+
else:
|
|
72
|
+
raise ClassiqInternalExpansionError("Failed to remove quantum var")
|
|
73
|
+
|
|
74
|
+
|
|
29
75
|
def _eval_type_attribute(
|
|
30
76
|
expr_val: QmodAnnotatedExpression, node: ast.Attribute
|
|
31
77
|
) -> None:
|
|
@@ -37,15 +83,22 @@ def _eval_type_attribute(
|
|
|
37
83
|
expr_val.set_type(node, Integer())
|
|
38
84
|
if subject_type.has_size_in_bits:
|
|
39
85
|
expr_val.set_value(node, subject_type.size_in_bits)
|
|
86
|
+
_remove_quantum_var(expr_val, subject)
|
|
40
87
|
else:
|
|
41
|
-
expr_val.set_quantum_type_attr(
|
|
88
|
+
expr_val.set_quantum_type_attr(
|
|
89
|
+
node, _get_symbolic_quantum_var(expr_val, subject), attr
|
|
90
|
+
)
|
|
42
91
|
return
|
|
43
92
|
if isinstance(subject_type, (ClassicalArray, QuantumBitvector)) and attr == "len":
|
|
44
93
|
expr_val.set_type(node, Integer())
|
|
45
|
-
if subject_type.
|
|
94
|
+
if subject_type.has_constant_length:
|
|
46
95
|
expr_val.set_value(node, subject_type.length_value)
|
|
96
|
+
if isinstance(subject_type, QuantumBitvector):
|
|
97
|
+
_remove_quantum_var(expr_val, subject)
|
|
47
98
|
elif isinstance(subject_type, QuantumType):
|
|
48
|
-
expr_val.set_quantum_type_attr(
|
|
99
|
+
expr_val.set_quantum_type_attr(
|
|
100
|
+
node, _get_symbolic_quantum_var(expr_val, subject), attr
|
|
101
|
+
)
|
|
49
102
|
return
|
|
50
103
|
if isinstance(subject_type, ClassicalTuple) and attr == "len":
|
|
51
104
|
expr_val.set_type(node, Integer())
|
|
@@ -56,19 +109,27 @@ def _eval_type_attribute(
|
|
|
56
109
|
expr_val.set_type(node, Bool())
|
|
57
110
|
if subject_type.has_sign:
|
|
58
111
|
expr_val.set_value(node, subject_type.sign_value)
|
|
112
|
+
_remove_quantum_var(expr_val, subject)
|
|
59
113
|
elif subject_type.has_size_in_bits:
|
|
60
114
|
expr_val.set_value(node, False)
|
|
115
|
+
_remove_quantum_var(expr_val, subject)
|
|
61
116
|
else:
|
|
62
|
-
expr_val.set_quantum_type_attr(
|
|
117
|
+
expr_val.set_quantum_type_attr(
|
|
118
|
+
node, _get_symbolic_quantum_var(expr_val, subject), attr
|
|
119
|
+
)
|
|
63
120
|
return
|
|
64
121
|
if attr == "fraction_digits":
|
|
65
122
|
expr_val.set_type(node, Integer())
|
|
66
123
|
if subject_type.has_fraction_digits:
|
|
67
124
|
expr_val.set_value(node, subject_type.fraction_digits_value)
|
|
125
|
+
_remove_quantum_var(expr_val, subject)
|
|
68
126
|
elif subject_type.has_size_in_bits:
|
|
69
127
|
expr_val.set_value(node, 0)
|
|
128
|
+
_remove_quantum_var(expr_val, subject)
|
|
70
129
|
else:
|
|
71
|
-
expr_val.set_quantum_type_attr(
|
|
130
|
+
expr_val.set_quantum_type_attr(
|
|
131
|
+
node, _get_symbolic_quantum_var(expr_val, subject), attr
|
|
132
|
+
)
|
|
72
133
|
return
|
|
73
134
|
raise ClassiqExpansionError(
|
|
74
135
|
f"{subject_type.raw_qmod_type_name} has no attribute {attr!r}"
|
|
@@ -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}")
|