classiq 0.89.0__py3-none-any.whl → 0.90.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/__init__.py +1 -0
- classiq/_internals/api_wrapper.py +16 -32
- classiq/analyzer/show_interactive_hack.py +26 -1
- classiq/applications/chemistry/chemistry_model_constructor.py +14 -2
- classiq/applications/combinatorial_helpers/pyomo_utils.py +9 -6
- classiq/applications/combinatorial_optimization/combinatorial_optimization_model_constructor.py +2 -2
- classiq/applications/combinatorial_optimization/combinatorial_problem.py +16 -8
- classiq/evaluators/classical_expression.py +63 -41
- classiq/evaluators/control.py +31 -52
- classiq/evaluators/expression_evaluator.py +8 -4
- classiq/evaluators/parameter_types.py +200 -104
- classiq/evaluators/qmod_annotated_expression.py +3 -1
- classiq/evaluators/qmod_node_evaluators/classical_function_evaluation.py +12 -37
- classiq/evaluators/qmod_node_evaluators/constant_evaluation.py +8 -17
- classiq/evaluators/qmod_node_evaluators/measurement_evaluation.py +1 -1
- classiq/evaluators/qmod_node_evaluators/min_max_evaluation.py +7 -1
- classiq/evaluators/qmod_node_evaluators/name_evaluation.py +0 -1
- classiq/evaluators/qmod_node_evaluators/numeric_attrs_utils.py +9 -1
- classiq/evaluators/qmod_node_evaluators/utils.py +33 -0
- classiq/evaluators/qmod_type_inference/classical_type_inference.py +4 -7
- classiq/interface/_version.py +1 -1
- classiq/interface/analyzer/analysis_params.py +1 -25
- classiq/interface/analyzer/result.py +4 -0
- classiq/interface/chemistry/ground_state_problem.py +16 -2
- classiq/interface/executor/optimizer_preferences.py +0 -112
- classiq/interface/generator/application_apis/chemistry_declarations.py +3 -1
- classiq/interface/generator/arith/arithmetic_expression_validator.py +2 -7
- classiq/interface/generator/expressions/evaluated_expression.py +3 -13
- classiq/interface/generator/expressions/expression_types.py +8 -22
- classiq/interface/generator/expressions/proxies/classical/classical_proxy.py +2 -2
- classiq/interface/generator/expressions/proxies/classical/classical_struct_proxy.py +1 -2
- classiq/interface/generator/functions/concrete_types.py +1 -1
- classiq/interface/generator/generated_circuit_data.py +4 -0
- classiq/interface/generator/preferences/qasm_to_qmod_params.py +14 -0
- classiq/interface/helpers/model_normalizer.py +0 -6
- classiq/interface/ide/visual_model.py +1 -0
- classiq/interface/model/handle_binding.py +1 -1
- classiq/interface/model/port_declaration.py +2 -1
- classiq/interface/model/quantum_expressions/arithmetic_operation.py +16 -12
- classiq/interface/model/quantum_type.py +1 -1
- classiq/interface/server/routes.py +2 -3
- classiq/model_expansions/atomic_expression_functions_defs.py +4 -22
- classiq/model_expansions/capturing/captured_vars.py +7 -3
- classiq/model_expansions/closure.py +8 -0
- classiq/model_expansions/interpreters/base_interpreter.py +84 -22
- classiq/model_expansions/interpreters/frontend_generative_interpreter.py +1 -1
- classiq/model_expansions/interpreters/generative_interpreter.py +7 -5
- classiq/model_expansions/quantum_operations/allocate.py +92 -21
- classiq/model_expansions/quantum_operations/assignment_result_processor.py +28 -27
- classiq/model_expansions/quantum_operations/call_emitter.py +32 -26
- classiq/model_expansions/quantum_operations/classical_var_emitter.py +6 -2
- classiq/model_expansions/quantum_operations/emitter.py +39 -69
- classiq/model_expansions/quantum_operations/expression_evaluator.py +13 -2
- classiq/model_expansions/quantum_operations/quantum_function_call.py +4 -5
- classiq/model_expansions/quantum_operations/variable_decleration.py +16 -11
- classiq/model_expansions/scope.py +36 -29
- classiq/model_expansions/scope_initialization.py +3 -6
- classiq/model_expansions/sympy_conversion/sympy_to_python.py +6 -2
- classiq/model_expansions/transformers/model_renamer.py +35 -64
- classiq/model_expansions/transformers/type_modifier_inference.py +6 -6
- classiq/model_expansions/visitors/boolean_expression_transformers.py +7 -31
- classiq/model_expansions/visitors/symbolic_param_inference.py +9 -3
- classiq/open_library/functions/state_preparation.py +3 -3
- classiq/qmod/builtins/functions/allocation.py +8 -8
- classiq/qmod/builtins/functions/arithmetic.py +1 -1
- classiq/qmod/builtins/functions/chemistry.py +64 -0
- classiq/qmod/builtins/functions/exponentiation.py +7 -13
- classiq/qmod/builtins/functions/qsvm.py +1 -1
- classiq/qmod/builtins/operations.py +38 -10
- classiq/qmod/generative.py +2 -4
- classiq/qmod/native/pretty_printer.py +1 -1
- classiq/qmod/pretty_print/pretty_printer.py +1 -1
- classiq/qmod/qmod_constant.py +1 -1
- classiq/qmod/qmod_parameter.py +2 -2
- classiq/qmod/qmod_variable.py +15 -15
- classiq/qmod/quantum_expandable.py +1 -1
- classiq/synthesis.py +37 -1
- classiq/visualization.py +1 -1
- {classiq-0.89.0.dist-info → classiq-0.90.0.dist-info}/METADATA +1 -1
- {classiq-0.89.0.dist-info → classiq-0.90.0.dist-info}/RECORD +81 -85
- classiq/evaluators/arg_type_match.py +0 -168
- classiq/evaluators/classical_type_inference.py +0 -121
- classiq/interface/combinatorial_optimization/optimization_problem.py +0 -17
- classiq/interface/combinatorial_optimization/result.py +0 -9
- classiq/model_expansions/transformers/ast_renamer.py +0 -26
- {classiq-0.89.0.dist-info → classiq-0.90.0.dist-info}/WHEEL +0 -0
|
@@ -15,6 +15,7 @@ from classiq.interface.generator.expressions.atomic_expression_functions import
|
|
|
15
15
|
from classiq.interface.generator.expressions.expression_types import (
|
|
16
16
|
ExpressionValue,
|
|
17
17
|
QmodStructInstance,
|
|
18
|
+
RuntimeConstant,
|
|
18
19
|
)
|
|
19
20
|
from classiq.interface.generator.expressions.proxies.classical.any_classical_value import (
|
|
20
21
|
AnyClassicalValue,
|
|
@@ -44,14 +45,12 @@ from classiq.interface.generator.functions.classical_type import (
|
|
|
44
45
|
ClassicalArray,
|
|
45
46
|
ClassicalTuple,
|
|
46
47
|
ClassicalType,
|
|
47
|
-
OpaqueHandle,
|
|
48
|
-
QmodPyObject,
|
|
49
48
|
Real,
|
|
50
|
-
StructMetaType,
|
|
51
49
|
)
|
|
52
50
|
from classiq.interface.generator.functions.type_name import TypeName
|
|
53
51
|
from classiq.interface.helpers.backward_compatibility import zip_strict
|
|
54
52
|
|
|
53
|
+
from classiq.evaluators.qmod_annotated_expression import QmodAnnotatedExpression
|
|
55
54
|
from classiq.evaluators.qmod_expression_visitors.sympy_wrappers import (
|
|
56
55
|
BitwiseAnd,
|
|
57
56
|
BitwiseNot,
|
|
@@ -61,10 +60,6 @@ from classiq.evaluators.qmod_expression_visitors.sympy_wrappers import (
|
|
|
61
60
|
LShift,
|
|
62
61
|
RShift,
|
|
63
62
|
)
|
|
64
|
-
from classiq.model_expansions.model_tables import (
|
|
65
|
-
HandleIdentifier,
|
|
66
|
-
HandleTable,
|
|
67
|
-
)
|
|
68
63
|
from classiq.model_expansions.sympy_conversion.expression_to_sympy import (
|
|
69
64
|
MISSING_SLICE_VALUE_PLACEHOLDER,
|
|
70
65
|
)
|
|
@@ -106,10 +101,6 @@ def qmod_val_to_python(val: ExpressionValue, qmod_type: ClassicalType) -> Any:
|
|
|
106
101
|
)
|
|
107
102
|
]
|
|
108
103
|
|
|
109
|
-
elif isinstance(qmod_type, OpaqueHandle):
|
|
110
|
-
if isinstance(val, HandleIdentifier):
|
|
111
|
-
return HandleTable.get_handle_object(val)
|
|
112
|
-
|
|
113
104
|
elif isinstance(val, Expr):
|
|
114
105
|
return sympy_to_python(val)
|
|
115
106
|
|
|
@@ -121,10 +112,6 @@ def qmod_val_to_python(val: ExpressionValue, qmod_type: ClassicalType) -> Any:
|
|
|
121
112
|
if isinstance(val, bool):
|
|
122
113
|
return val
|
|
123
114
|
|
|
124
|
-
elif isinstance(qmod_type, StructMetaType):
|
|
125
|
-
if isinstance(val, TypeProxy):
|
|
126
|
-
return val.struct_declaration
|
|
127
|
-
|
|
128
115
|
elif isinstance(val, int): # other scalars are represented as int
|
|
129
116
|
return val
|
|
130
117
|
|
|
@@ -162,11 +149,6 @@ def python_val_to_qmod(val: Any, qmod_type: ClassicalType) -> ExpressionValue:
|
|
|
162
149
|
for elem, elem_type in zip_strict(val, qmod_type.element_types, strict=True)
|
|
163
150
|
]
|
|
164
151
|
|
|
165
|
-
if isinstance(qmod_type, OpaqueHandle):
|
|
166
|
-
if not isinstance(val, QmodPyObject):
|
|
167
|
-
raise ClassiqInternalExpansionError("Bad value opaque handle")
|
|
168
|
-
return HandleTable.set_handle_object(val)
|
|
169
|
-
|
|
170
152
|
return val
|
|
171
153
|
|
|
172
154
|
|
|
@@ -194,7 +176,7 @@ def get_field(
|
|
|
194
176
|
QmodSizedProxy, QmodStructInstance, list, ClassicalProxy, AnyClassicalValue
|
|
195
177
|
],
|
|
196
178
|
field: str,
|
|
197
|
-
) ->
|
|
179
|
+
) -> Any:
|
|
198
180
|
if isinstance(proxy, AnyClassicalValue) or (
|
|
199
181
|
isinstance(proxy, Symbol)
|
|
200
182
|
and not isinstance(proxy, QmodSizedProxy)
|
|
@@ -244,7 +226,7 @@ def do_div(lhs: Any, rhs: Any) -> Any:
|
|
|
244
226
|
return res
|
|
245
227
|
|
|
246
228
|
|
|
247
|
-
_EXPRESSION_TYPES = get_args(
|
|
229
|
+
_EXPRESSION_TYPES = (*get_args(RuntimeConstant), QmodAnnotatedExpression)
|
|
248
230
|
|
|
249
231
|
|
|
250
232
|
def _is_qmod_value(val: Any) -> bool:
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import ast
|
|
1
2
|
import dataclasses
|
|
2
3
|
from collections.abc import Sequence
|
|
3
4
|
from dataclasses import dataclass, field
|
|
@@ -41,6 +42,7 @@ from classiq.interface.model.variable_declaration_statement import (
|
|
|
41
42
|
VariableDeclarationStatement,
|
|
42
43
|
)
|
|
43
44
|
|
|
45
|
+
from classiq.evaluators.qmod_annotated_expression import QmodAnnotatedExpression
|
|
44
46
|
from classiq.model_expansions.capturing.mangling_utils import (
|
|
45
47
|
demangle_handle,
|
|
46
48
|
mangle_captured_var_name,
|
|
@@ -60,9 +62,11 @@ UNINITIALIZED_VAR_MESSAGE = "Variable '{}' should be initialized here"
|
|
|
60
62
|
|
|
61
63
|
def _get_symbol_expr(symbol: str, classical_type: ClassicalType) -> Expression:
|
|
62
64
|
expr = Expression(expr=symbol)
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
)
|
|
65
|
+
expr_val = QmodAnnotatedExpression(ast.Name(id=symbol))
|
|
66
|
+
expr_val.set_type(expr_val.root, classical_type)
|
|
67
|
+
expr_val.set_var(expr_val.root, HandleBinding(name=symbol))
|
|
68
|
+
expr_val.lock()
|
|
69
|
+
expr._evaluated_expr = EvaluatedExpression(value=expr_val)
|
|
66
70
|
return expr
|
|
67
71
|
|
|
68
72
|
|
|
@@ -11,6 +11,7 @@ from classiq.interface.helpers.pydantic_model_helpers import nameables_to_dict
|
|
|
11
11
|
from classiq.interface.model.quantum_function_declaration import (
|
|
12
12
|
NamedParamsQuantumFunctionDeclaration,
|
|
13
13
|
PositionalArg,
|
|
14
|
+
QuantumOperandDeclaration,
|
|
14
15
|
)
|
|
15
16
|
from classiq.interface.model.quantum_lambda_function import QuantumCallable
|
|
16
17
|
from classiq.interface.model.quantum_statement import QuantumStatement
|
|
@@ -111,6 +112,13 @@ class FunctionClosure(Closure):
|
|
|
111
112
|
def emit(self) -> QuantumCallable:
|
|
112
113
|
return self.name
|
|
113
114
|
|
|
115
|
+
def as_operand_declaration(self, is_list: bool) -> QuantumOperandDeclaration:
|
|
116
|
+
return QuantumOperandDeclaration(
|
|
117
|
+
name=self.name,
|
|
118
|
+
positional_arg_declarations=self.positional_arg_declarations,
|
|
119
|
+
is_list=is_list,
|
|
120
|
+
)
|
|
121
|
+
|
|
114
122
|
|
|
115
123
|
@dataclass(frozen=True)
|
|
116
124
|
class GenerativeFunctionClosure(GenerativeClosure, FunctionClosure):
|
|
@@ -4,7 +4,7 @@ from collections import defaultdict
|
|
|
4
4
|
from collections.abc import Sequence
|
|
5
5
|
from contextlib import nullcontext
|
|
6
6
|
from functools import singledispatchmethod
|
|
7
|
-
from typing import Any, cast
|
|
7
|
+
from typing import Any, Callable, cast
|
|
8
8
|
|
|
9
9
|
from pydantic import ValidationError
|
|
10
10
|
|
|
@@ -16,10 +16,8 @@ from classiq.interface.exceptions import (
|
|
|
16
16
|
ClassiqExpansionError,
|
|
17
17
|
ClassiqInternalExpansionError,
|
|
18
18
|
)
|
|
19
|
-
from classiq.interface.generator.expressions.atomic_expression_functions import (
|
|
20
|
-
CLASSICAL_ATTRIBUTES,
|
|
21
|
-
)
|
|
22
19
|
from classiq.interface.generator.expressions.expression import Expression
|
|
20
|
+
from classiq.interface.generator.expressions.expression_types import ExpressionValue
|
|
23
21
|
from classiq.interface.generator.functions.classical_function_declaration import (
|
|
24
22
|
ClassicalFunctionDeclaration,
|
|
25
23
|
)
|
|
@@ -42,8 +40,20 @@ from classiq.interface.model.quantum_lambda_function import (
|
|
|
42
40
|
)
|
|
43
41
|
from classiq.interface.model.quantum_statement import QuantumStatement
|
|
44
42
|
|
|
45
|
-
from classiq.evaluators.classical_expression import
|
|
46
|
-
|
|
43
|
+
from classiq.evaluators.classical_expression import process_scope_val
|
|
44
|
+
from classiq.evaluators.qmod_annotated_expression import QmodAnnotatedExpression
|
|
45
|
+
from classiq.evaluators.qmod_expression_visitors.qmod_expression_bwc import (
|
|
46
|
+
QmodExpressionBwc,
|
|
47
|
+
)
|
|
48
|
+
from classiq.evaluators.qmod_expression_visitors.qmod_expression_evaluator import (
|
|
49
|
+
evaluate_qmod_expression,
|
|
50
|
+
)
|
|
51
|
+
from classiq.evaluators.qmod_expression_visitors.qmod_expression_simplifier import (
|
|
52
|
+
simplify_qmod_expression,
|
|
53
|
+
)
|
|
54
|
+
from classiq.evaluators.qmod_node_evaluators.utils import is_classical_integer
|
|
55
|
+
from classiq.evaluators.qmod_type_inference.classical_type_inference import (
|
|
56
|
+
infer_classical_type,
|
|
47
57
|
)
|
|
48
58
|
from classiq.model_expansions.closure import (
|
|
49
59
|
Closure,
|
|
@@ -67,7 +77,6 @@ from classiq.model_expansions.scope_initialization import (
|
|
|
67
77
|
init_top_level_scope,
|
|
68
78
|
)
|
|
69
79
|
from classiq.model_expansions.utils.counted_name_allocator import CountedNameAllocator
|
|
70
|
-
from classiq.model_expansions.visitors.variable_references import VarRefCollector
|
|
71
80
|
from classiq.qmod.builtins.constants import __all__ as builtin_constants
|
|
72
81
|
from classiq.qmod.builtins.enums import BUILTIN_ENUM_DECLARATIONS
|
|
73
82
|
from classiq.qmod.builtins.structs import BUILTIN_STRUCT_DECLARATIONS
|
|
@@ -75,7 +84,17 @@ from classiq.qmod.model_state_container import QMODULE
|
|
|
75
84
|
from classiq.qmod.semantics.annotation.qstruct_annotator import QStructAnnotator
|
|
76
85
|
from classiq.qmod.semantics.error_manager import ErrorManager
|
|
77
86
|
from classiq.qmod.semantics.validation.model_validation import validate_model
|
|
78
|
-
|
|
87
|
+
|
|
88
|
+
|
|
89
|
+
def _validate_index(val: ExpressionValue, subject: str) -> None:
|
|
90
|
+
if isinstance(val, QmodAnnotatedExpression):
|
|
91
|
+
val_type = val.get_type(val.root)
|
|
92
|
+
else:
|
|
93
|
+
val_type = infer_classical_type(val)
|
|
94
|
+
if not is_classical_integer(val_type):
|
|
95
|
+
raise ClassiqExpansionError(
|
|
96
|
+
f"{subject} indices must be integers, not {val_type.raw_qmod_type_name}"
|
|
97
|
+
)
|
|
79
98
|
|
|
80
99
|
|
|
81
100
|
class BaseInterpreter:
|
|
@@ -130,6 +149,12 @@ class BaseInterpreter:
|
|
|
130
149
|
try:
|
|
131
150
|
with self._error_manager.call("main"):
|
|
132
151
|
self._expand_main_func()
|
|
152
|
+
except RecursionError:
|
|
153
|
+
self._error_manager.add_error(
|
|
154
|
+
"RecursionError: maximum recursion depth exceeded. Tip: If your "
|
|
155
|
+
"program contains recursive functions, check for base cases using a "
|
|
156
|
+
"Python if-statement (instead of Qmod's `if_`)"
|
|
157
|
+
)
|
|
133
158
|
except Exception as e:
|
|
134
159
|
if isinstance(e, ClassiqInternalExpansionError) or debug_mode.get():
|
|
135
160
|
raise e
|
|
@@ -175,22 +200,56 @@ class BaseInterpreter:
|
|
|
175
200
|
def evaluate(self, expression: Any) -> Evaluated:
|
|
176
201
|
raise NotImplementedError(f"Cannot evaluate {expression!r}")
|
|
177
202
|
|
|
203
|
+
def get_foreign_functions(self) -> dict[str, Callable]:
|
|
204
|
+
return {}
|
|
205
|
+
|
|
178
206
|
@evaluate.register
|
|
179
|
-
def evaluate_classical_expression(
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
207
|
+
def evaluate_classical_expression(
|
|
208
|
+
self,
|
|
209
|
+
expression: Expression,
|
|
210
|
+
*,
|
|
211
|
+
simplify: bool = False,
|
|
212
|
+
treat_qnum_as_float: bool = False,
|
|
213
|
+
) -> Evaluated:
|
|
214
|
+
if expression.is_evaluated():
|
|
215
|
+
return Evaluated(value=expression.value.value)
|
|
216
|
+
expr_ast = ast.parse(expression.expr, mode="eval").body
|
|
217
|
+
expr_ast = QmodExpressionBwc().visit(expr_ast)
|
|
218
|
+
expr_val = self._eval_expr(ast.unparse(expr_ast), treat_qnum_as_float)
|
|
219
|
+
if simplify and not expr_val.has_value(expr_val.root):
|
|
220
|
+
simplified_expr = simplify_qmod_expression(expr_val)
|
|
221
|
+
expr_val = self._eval_expr(simplified_expr, treat_qnum_as_float)
|
|
222
|
+
if expr_val.has_value(expr_val.root):
|
|
223
|
+
value = expr_val.get_value(expr_val.root)
|
|
224
|
+
else:
|
|
225
|
+
value = expr_val
|
|
226
|
+
|
|
227
|
+
return Evaluated(value=value)
|
|
228
|
+
|
|
229
|
+
def _eval_expr(
|
|
230
|
+
self, expr: str, treat_qnum_as_float: bool
|
|
231
|
+
) -> QmodAnnotatedExpression:
|
|
232
|
+
return evaluate_qmod_expression(
|
|
233
|
+
expr,
|
|
234
|
+
treat_qnum_as_float=treat_qnum_as_float,
|
|
235
|
+
machine_precision=self._model.preferences.machine_precision,
|
|
236
|
+
classical_struct_declarations=list(QMODULE.type_decls.values()),
|
|
237
|
+
enum_declarations=list(QMODULE.enum_decls.values()),
|
|
238
|
+
classical_function_declarations=list(
|
|
239
|
+
ClassicalFunctionDeclaration.FOREIGN_FUNCTION_DECLARATIONS.values()
|
|
240
|
+
),
|
|
241
|
+
classical_function_callables=self.get_foreign_functions(),
|
|
242
|
+
scope={
|
|
243
|
+
name: processed_val
|
|
244
|
+
for name in list(self._builder.current_scope)
|
|
187
245
|
if (
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
246
|
+
processed_val := process_scope_val(
|
|
247
|
+
self._builder.current_scope[name].value
|
|
248
|
+
)
|
|
249
|
+
)
|
|
250
|
+
is not None
|
|
251
|
+
},
|
|
252
|
+
)
|
|
194
253
|
|
|
195
254
|
@evaluate.register
|
|
196
255
|
def evaluate_identifier(self, identifier: str) -> Evaluated:
|
|
@@ -216,6 +275,8 @@ class BaseInterpreter:
|
|
|
216
275
|
)
|
|
217
276
|
start = self.evaluate(sliced_handle_binding.start).value
|
|
218
277
|
end = self.evaluate(sliced_handle_binding.end).value
|
|
278
|
+
_validate_index(start, "Slice")
|
|
279
|
+
_validate_index(end, "Slice")
|
|
219
280
|
return Evaluated(value=quantum_variable[start:end])
|
|
220
281
|
|
|
221
282
|
@evaluate.register
|
|
@@ -232,6 +293,7 @@ class BaseInterpreter:
|
|
|
232
293
|
def evaluate_subscript_operand(self, subscript: OperandIdentifier) -> Evaluated:
|
|
233
294
|
base_value = self.evaluate(subscript.name)
|
|
234
295
|
index_value = self.evaluate(subscript.index).as_type(int)
|
|
296
|
+
_validate_index(index_value, "Array")
|
|
235
297
|
return Evaluated(value=base_value.value[index_value])
|
|
236
298
|
|
|
237
299
|
@evaluate.register
|
|
@@ -45,7 +45,7 @@ class FrontendGenerativeInterpreter(GenerativeInterpreter):
|
|
|
45
45
|
return super()._get_main_closure(main_func)
|
|
46
46
|
|
|
47
47
|
def process_exception(self, e: Exception) -> None:
|
|
48
|
-
if not isinstance(e, (ClassiqError, ValidationError)):
|
|
48
|
+
if not isinstance(e, (ClassiqError, ValidationError, RecursionError)):
|
|
49
49
|
frame = inspect.trace()[-1]
|
|
50
50
|
module = inspect.getmodule(frame[0])
|
|
51
51
|
if module is None or not module.__name__.startswith("classiq."):
|
|
@@ -183,7 +183,9 @@ class GenerativeInterpreter(BaseInterpreter):
|
|
|
183
183
|
self,
|
|
184
184
|
[
|
|
185
185
|
HandleEvaluator(self, "result_var"),
|
|
186
|
-
ExpressionEvaluator(
|
|
186
|
+
ExpressionEvaluator(
|
|
187
|
+
self, "expression", simplify=True, treat_qnum_as_float=True
|
|
188
|
+
),
|
|
187
189
|
AssignmentResultProcessor(self),
|
|
188
190
|
],
|
|
189
191
|
).emit(op)
|
|
@@ -197,7 +199,7 @@ class GenerativeInterpreter(BaseInterpreter):
|
|
|
197
199
|
self,
|
|
198
200
|
[
|
|
199
201
|
HandleEvaluator(self, "result_var"),
|
|
200
|
-
ExpressionEvaluator(self, "expression"),
|
|
202
|
+
ExpressionEvaluator(self, "expression", simplify=True),
|
|
201
203
|
ClassicalVarEmitter(self),
|
|
202
204
|
AssignmentResultProcessor(self),
|
|
203
205
|
],
|
|
@@ -210,7 +212,7 @@ class GenerativeInterpreter(BaseInterpreter):
|
|
|
210
212
|
[
|
|
211
213
|
HandleEvaluator(self, "target"),
|
|
212
214
|
HandleEvaluator(self, "value"),
|
|
213
|
-
ExpressionEvaluator(self, "value"),
|
|
215
|
+
ExpressionEvaluator(self, "value", simplify=True),
|
|
214
216
|
],
|
|
215
217
|
).emit(op)
|
|
216
218
|
|
|
@@ -276,7 +278,7 @@ class GenerativeInterpreter(BaseInterpreter):
|
|
|
276
278
|
CompositeEmitter[Control](
|
|
277
279
|
self,
|
|
278
280
|
[
|
|
279
|
-
ExpressionEvaluator(self, "expression"),
|
|
281
|
+
ExpressionEvaluator(self, "expression", simplify=True),
|
|
280
282
|
BlockEvaluator(
|
|
281
283
|
self,
|
|
282
284
|
CONTROL_OPERATOR_NAME,
|
|
@@ -301,7 +303,7 @@ class GenerativeInterpreter(BaseInterpreter):
|
|
|
301
303
|
CompositeEmitter[PhaseOperation](
|
|
302
304
|
self,
|
|
303
305
|
[
|
|
304
|
-
ExpressionEvaluator(self, "expression"),
|
|
306
|
+
ExpressionEvaluator(self, "expression", simplify=True),
|
|
305
307
|
ExpressionEvaluator(self, "theta"),
|
|
306
308
|
],
|
|
307
309
|
).emit(phase)
|
|
@@ -1,10 +1,16 @@
|
|
|
1
|
-
from typing import TYPE_CHECKING, Union
|
|
1
|
+
from typing import TYPE_CHECKING, Any, Union
|
|
2
2
|
|
|
3
3
|
import sympy
|
|
4
4
|
|
|
5
5
|
from classiq.interface.debug_info.debug_info import FunctionDebugInfo
|
|
6
6
|
from classiq.interface.exceptions import ClassiqExpansionError, ClassiqValueError
|
|
7
|
+
from classiq.interface.generator.expressions.evaluated_expression import (
|
|
8
|
+
EvaluatedExpression,
|
|
9
|
+
)
|
|
7
10
|
from classiq.interface.generator.expressions.expression import Expression
|
|
11
|
+
from classiq.interface.generator.expressions.expression_types import ExpressionValue
|
|
12
|
+
from classiq.interface.generator.functions.classical_type import Bool, Integer, Real
|
|
13
|
+
from classiq.interface.helpers.text_utils import s
|
|
8
14
|
from classiq.interface.model.allocate import Allocate
|
|
9
15
|
from classiq.interface.model.handle_binding import NestedHandleBinding
|
|
10
16
|
from classiq.interface.model.quantum_type import (
|
|
@@ -12,6 +18,8 @@ from classiq.interface.model.quantum_type import (
|
|
|
12
18
|
QuantumNumeric,
|
|
13
19
|
)
|
|
14
20
|
|
|
21
|
+
from classiq.evaluators.qmod_annotated_expression import QmodAnnotatedExpression
|
|
22
|
+
from classiq.evaluators.qmod_node_evaluators.utils import get_sympy_type
|
|
15
23
|
from classiq.evaluators.qmod_type_inference.quantum_type_inference import (
|
|
16
24
|
inject_quantum_type_attributes_inplace,
|
|
17
25
|
)
|
|
@@ -22,6 +30,13 @@ if TYPE_CHECKING:
|
|
|
22
30
|
from classiq.model_expansions.interpreters.base_interpreter import BaseInterpreter
|
|
23
31
|
|
|
24
32
|
|
|
33
|
+
def _assign_attr(
|
|
34
|
+
op_update_dict: dict[str, Expression], attr: str, size_value: ExpressionValue
|
|
35
|
+
) -> None:
|
|
36
|
+
op_update_dict[attr] = Expression(expr=str(size_value))
|
|
37
|
+
op_update_dict[attr]._evaluated_expr = EvaluatedExpression(value=size_value)
|
|
38
|
+
|
|
39
|
+
|
|
25
40
|
class AllocateEmitter(Emitter[Allocate]):
|
|
26
41
|
def __init__(
|
|
27
42
|
self, interpreter: "BaseInterpreter", allow_symbolic_attrs: bool = False
|
|
@@ -86,7 +101,7 @@ class AllocateEmitter(Emitter[Allocate]):
|
|
|
86
101
|
raise ClassiqValueError(
|
|
87
102
|
f"Could not infer the size of variable {str(target.handle)!r}"
|
|
88
103
|
)
|
|
89
|
-
op_update_dict["size"] = Expression(expr=expr)
|
|
104
|
+
op_update_dict["size"] = self._evaluate_expression(Expression(expr=expr))
|
|
90
105
|
|
|
91
106
|
def _handle_with_size(
|
|
92
107
|
self,
|
|
@@ -95,10 +110,10 @@ class AllocateEmitter(Emitter[Allocate]):
|
|
|
95
110
|
op_update_dict: dict[str, Expression],
|
|
96
111
|
) -> None:
|
|
97
112
|
size_value = self._interpret_size(size, str(target.handle))
|
|
98
|
-
op_update_dict
|
|
113
|
+
_assign_attr(op_update_dict, "size", size_value)
|
|
99
114
|
|
|
100
115
|
if not isinstance(
|
|
101
|
-
size_value,
|
|
116
|
+
size_value, QmodAnnotatedExpression
|
|
102
117
|
) and not inject_quantum_type_attributes_inplace(
|
|
103
118
|
QuantumBitvector(length=op_update_dict["size"]), target.quantum_type
|
|
104
119
|
):
|
|
@@ -122,16 +137,19 @@ class AllocateEmitter(Emitter[Allocate]):
|
|
|
122
137
|
)
|
|
123
138
|
|
|
124
139
|
size_value = self._interpret_size(size, var_name)
|
|
125
|
-
op_update_dict
|
|
140
|
+
_assign_attr(op_update_dict, "size", size_value)
|
|
126
141
|
is_signed_value = self._interpret_is_signed(is_signed)
|
|
127
|
-
op_update_dict
|
|
142
|
+
_assign_attr(op_update_dict, "is_signed", is_signed_value)
|
|
128
143
|
fraction_digits_value = self._interpret_fraction_digits(fraction_digits)
|
|
129
|
-
op_update_dict
|
|
144
|
+
_assign_attr(op_update_dict, "fraction_digits", fraction_digits_value)
|
|
145
|
+
self._validate_numeric_atrributes(
|
|
146
|
+
var_name, size_value, is_signed_value, fraction_digits_value
|
|
147
|
+
)
|
|
130
148
|
|
|
131
149
|
if not (
|
|
132
|
-
isinstance(size_value,
|
|
133
|
-
or isinstance(is_signed_value,
|
|
134
|
-
or isinstance(fraction_digits_value,
|
|
150
|
+
isinstance(size_value, QmodAnnotatedExpression)
|
|
151
|
+
or isinstance(is_signed_value, QmodAnnotatedExpression)
|
|
152
|
+
or isinstance(fraction_digits_value, QmodAnnotatedExpression)
|
|
135
153
|
) and not inject_quantum_type_attributes_inplace(
|
|
136
154
|
QuantumNumeric(
|
|
137
155
|
size=op_update_dict["size"],
|
|
@@ -145,24 +163,73 @@ class AllocateEmitter(Emitter[Allocate]):
|
|
|
145
163
|
f"{var_name!r} of type {target.quantum_type.qmod_type_name}"
|
|
146
164
|
)
|
|
147
165
|
|
|
166
|
+
def _validate_numeric_atrributes(
|
|
167
|
+
self,
|
|
168
|
+
var_name: str,
|
|
169
|
+
size_value: Any,
|
|
170
|
+
is_signed_value: Any,
|
|
171
|
+
fraction_digits_value: Any,
|
|
172
|
+
) -> None:
|
|
173
|
+
if (
|
|
174
|
+
isinstance(size_value, int)
|
|
175
|
+
and isinstance(is_signed_value, bool)
|
|
176
|
+
and isinstance(fraction_digits_value, int)
|
|
177
|
+
):
|
|
178
|
+
if size_value < 0:
|
|
179
|
+
raise ClassiqValueError(
|
|
180
|
+
f"Cannot allocate {size_value} qubit{s(size_value)} for variable "
|
|
181
|
+
f"{var_name!r}"
|
|
182
|
+
)
|
|
183
|
+
if fraction_digits_value < 0:
|
|
184
|
+
raise ClassiqValueError(
|
|
185
|
+
f"Variable {var_name!r} cannot have a negative number of fraction "
|
|
186
|
+
f"digits (got {fraction_digits_value})"
|
|
187
|
+
)
|
|
188
|
+
if size_value < fraction_digits_value:
|
|
189
|
+
raise ClassiqValueError(
|
|
190
|
+
f"Cannot allocate {size_value} qubit{s(size_value)} for variable "
|
|
191
|
+
f"{var_name!r} with {fraction_digits_value} fraction digits"
|
|
192
|
+
)
|
|
193
|
+
|
|
148
194
|
def _interpret_size(
|
|
149
195
|
self, size: Expression, var_name: str
|
|
150
|
-
) -> Union[int, float, sympy.Basic]:
|
|
196
|
+
) -> Union[int, float, sympy.Basic, QmodAnnotatedExpression]:
|
|
151
197
|
size_value = self._interpreter.evaluate(size).value
|
|
152
|
-
if not
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
198
|
+
if not (
|
|
199
|
+
(
|
|
200
|
+
isinstance(size_value, QmodAnnotatedExpression)
|
|
201
|
+
and isinstance(size_value.get_type(size_value.root), (Integer, Real))
|
|
202
|
+
)
|
|
203
|
+
or isinstance(size_value, (int, float))
|
|
204
|
+
or (
|
|
205
|
+
isinstance(size_value, sympy.Basic)
|
|
206
|
+
and isinstance(get_sympy_type(size_value), (Integer, Real))
|
|
207
|
+
)
|
|
208
|
+
):
|
|
157
209
|
raise ClassiqValueError(
|
|
158
210
|
f"The number of allocated qubits must be an integer. Got "
|
|
159
211
|
f"{str(size_value)!r}"
|
|
160
212
|
)
|
|
213
|
+
if (
|
|
214
|
+
isinstance(size_value, QmodAnnotatedExpression)
|
|
215
|
+
and not self._allow_symbolic_attrs
|
|
216
|
+
):
|
|
217
|
+
raise ClassiqValueError(
|
|
218
|
+
f"Could not infer the size of variable {var_name!r}"
|
|
219
|
+
)
|
|
161
220
|
return size_value
|
|
162
221
|
|
|
163
|
-
def _interpret_is_signed(
|
|
222
|
+
def _interpret_is_signed(
|
|
223
|
+
self, is_signed: Expression
|
|
224
|
+
) -> Union[bool, sympy.Basic, QmodAnnotatedExpression]:
|
|
164
225
|
is_signed_value = self._interpreter.evaluate(is_signed).value
|
|
165
|
-
if not self._allow_symbolic_attrs and not
|
|
226
|
+
if not self._allow_symbolic_attrs and not (
|
|
227
|
+
isinstance(is_signed_value, bool)
|
|
228
|
+
or (
|
|
229
|
+
isinstance(is_signed_value, sympy.Basic)
|
|
230
|
+
and isinstance(get_sympy_type(is_signed_value), Bool)
|
|
231
|
+
)
|
|
232
|
+
):
|
|
166
233
|
raise ClassiqValueError(
|
|
167
234
|
f"The sign of a variable must be boolean. Got "
|
|
168
235
|
f"{str(is_signed_value)!r}"
|
|
@@ -171,10 +238,14 @@ class AllocateEmitter(Emitter[Allocate]):
|
|
|
171
238
|
|
|
172
239
|
def _interpret_fraction_digits(
|
|
173
240
|
self, fraction_digits: Expression
|
|
174
|
-
) -> Union[int, float, sympy.
|
|
241
|
+
) -> Union[int, float, sympy.Expr, QmodAnnotatedExpression]:
|
|
175
242
|
fraction_digits_value = self._interpreter.evaluate(fraction_digits).value
|
|
176
|
-
if not self._allow_symbolic_attrs and not
|
|
177
|
-
fraction_digits_value, (int, float)
|
|
243
|
+
if not self._allow_symbolic_attrs and not (
|
|
244
|
+
isinstance(fraction_digits_value, (int, float))
|
|
245
|
+
or (
|
|
246
|
+
isinstance(fraction_digits_value, sympy.Expr)
|
|
247
|
+
and fraction_digits_value.is_integer
|
|
248
|
+
)
|
|
178
249
|
):
|
|
179
250
|
raise ClassiqValueError(
|
|
180
251
|
f"The fraction digits of a variable must be an integer. Got "
|
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
from typing import TYPE_CHECKING, Optional
|
|
2
2
|
|
|
3
3
|
from classiq.interface.exceptions import ClassiqExpansionError
|
|
4
|
-
from classiq.interface.generator.arith.arithmetic import compute_arithmetic_result_type
|
|
5
4
|
from classiq.interface.generator.expressions.expression import Expression
|
|
6
5
|
from classiq.interface.model.allocate import Allocate
|
|
7
6
|
from classiq.interface.model.bind_operation import BindOperation
|
|
@@ -20,23 +19,31 @@ from classiq.interface.model.quantum_expressions.quantum_expression import (
|
|
|
20
19
|
QuantumAssignmentOperation,
|
|
21
20
|
)
|
|
22
21
|
from classiq.interface.model.quantum_function_call import QuantumFunctionCall
|
|
23
|
-
from classiq.interface.model.quantum_type import
|
|
22
|
+
from classiq.interface.model.quantum_type import (
|
|
23
|
+
QuantumBitvector,
|
|
24
|
+
QuantumNumeric,
|
|
25
|
+
QuantumScalar,
|
|
26
|
+
)
|
|
24
27
|
from classiq.interface.model.statement_block import StatementBlock
|
|
25
28
|
from classiq.interface.model.variable_declaration_statement import (
|
|
26
29
|
VariableDeclarationStatement,
|
|
27
30
|
)
|
|
28
31
|
from classiq.interface.model.within_apply_operation import WithinApply
|
|
29
32
|
|
|
33
|
+
from classiq.evaluators.qmod_annotated_expression import QmodAnnotatedExpression
|
|
30
34
|
from classiq.evaluators.qmod_type_inference.quantum_type_inference import (
|
|
31
35
|
inject_quantum_type_attributes_inplace,
|
|
32
36
|
)
|
|
37
|
+
from classiq.model_expansions.arithmetic import NumericAttributes
|
|
38
|
+
from classiq.model_expansions.arithmetic_compute_result_attrs import (
|
|
39
|
+
compute_result_attrs_assign,
|
|
40
|
+
)
|
|
33
41
|
from classiq.model_expansions.quantum_operations.arithmetic.explicit_boolean_expressions import (
|
|
34
42
|
convert_assignment_bool_expression,
|
|
35
43
|
validate_assignment_bool_expression,
|
|
36
44
|
)
|
|
37
45
|
from classiq.model_expansions.quantum_operations.emitter import Emitter
|
|
38
46
|
from classiq.model_expansions.scope import ClassicalSymbol
|
|
39
|
-
from classiq.model_expansions.transformers.ast_renamer import rename_variables
|
|
40
47
|
from classiq.qmod.builtins.functions.standard_gates import CX
|
|
41
48
|
|
|
42
49
|
if TYPE_CHECKING:
|
|
@@ -100,33 +107,27 @@ class AssignmentResultProcessor(Emitter[QuantumAssignmentOperation]):
|
|
|
100
107
|
|
|
101
108
|
def _infer_expression_type(
|
|
102
109
|
self, op: ArithmeticOperation
|
|
103
|
-
) -> Optional[
|
|
110
|
+
) -> Optional[QuantumScalar]:
|
|
104
111
|
expr = self._evaluate_expression(op.expression)
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
112
|
+
expr_val = expr.value.value
|
|
113
|
+
if isinstance(expr_val, QmodAnnotatedExpression):
|
|
114
|
+
root_type = expr_val.get_type(expr_val.root)
|
|
115
|
+
if isinstance(root_type, QuantumScalar) and root_type.is_instantiated:
|
|
116
|
+
root_type = compute_result_attrs_assign(
|
|
117
|
+
NumericAttributes.from_type_or_constant(root_type),
|
|
118
|
+
self._machine_precision,
|
|
119
|
+
).to_quantum_numeric()
|
|
120
|
+
return root_type
|
|
110
121
|
return None
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
)
|
|
117
|
-
for symbol in symbols:
|
|
118
|
-
expr_str = expr_str.replace(
|
|
119
|
-
symbol.handle.qmod_expr, symbol.handle.identifier
|
|
120
|
-
)
|
|
121
|
-
return compute_arithmetic_result_type(
|
|
122
|
-
expr_str,
|
|
123
|
-
{symbol.handle.identifier: symbol.quantum_type for symbol in symbols},
|
|
124
|
-
self._machine_precision,
|
|
125
|
-
)
|
|
122
|
+
if isinstance(expr_val, (int, float)):
|
|
123
|
+
return NumericAttributes.from_constant(
|
|
124
|
+
expr_val, self._machine_precision
|
|
125
|
+
).to_quantum_numeric()
|
|
126
|
+
return None
|
|
126
127
|
|
|
127
128
|
@staticmethod
|
|
128
129
|
def _same_numeric_attributes(
|
|
129
|
-
result_type: QuantumNumeric, expression_type:
|
|
130
|
+
result_type: QuantumNumeric, expression_type: QuantumScalar
|
|
130
131
|
) -> bool:
|
|
131
132
|
return (
|
|
132
133
|
result_type.size_in_bits == expression_type.size_in_bits
|
|
@@ -137,7 +138,7 @@ class AssignmentResultProcessor(Emitter[QuantumAssignmentOperation]):
|
|
|
137
138
|
|
|
138
139
|
@classmethod
|
|
139
140
|
def _validate_declared_attributes(
|
|
140
|
-
cls, result_type: QuantumNumeric, expression_type:
|
|
141
|
+
cls, result_type: QuantumNumeric, expression_type: QuantumScalar, var: str
|
|
141
142
|
) -> None:
|
|
142
143
|
result_size, result_sign, result_fractions = (
|
|
143
144
|
result_type.size_in_bits,
|
|
@@ -183,7 +184,7 @@ class AssignmentResultProcessor(Emitter[QuantumAssignmentOperation]):
|
|
|
183
184
|
self,
|
|
184
185
|
op: ArithmeticOperation,
|
|
185
186
|
result_type: QuantumNumeric,
|
|
186
|
-
expression_type:
|
|
187
|
+
expression_type: QuantumScalar,
|
|
187
188
|
) -> None:
|
|
188
189
|
stmts: StatementBlock = []
|
|
189
190
|
handles: list[HandleBinding] = []
|