classiq 0.86.1__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/__init__.py +2 -0
- classiq/applications/__init__.py +1 -2
- classiq/applications/chemistry/hartree_fock.py +5 -1
- classiq/applications/chemistry/op_utils.py +2 -2
- classiq/applications/combinatorial_helpers/combinatorial_problem_utils.py +1 -1
- classiq/applications/combinatorial_helpers/encoding_mapping.py +11 -15
- classiq/applications/combinatorial_helpers/encoding_utils.py +6 -6
- classiq/applications/combinatorial_helpers/memory.py +4 -4
- classiq/applications/combinatorial_helpers/optimization_model.py +5 -5
- classiq/applications/combinatorial_helpers/pauli_helpers/pauli_utils.py +6 -10
- classiq/applications/combinatorial_helpers/pyomo_utils.py +27 -26
- classiq/applications/combinatorial_helpers/sympy_utils.py +2 -2
- classiq/applications/combinatorial_helpers/transformations/encoding.py +4 -6
- classiq/applications/combinatorial_helpers/transformations/fixed_variables.py +4 -4
- classiq/applications/combinatorial_helpers/transformations/ising_converter.py +2 -2
- classiq/applications/combinatorial_helpers/transformations/penalty_support.py +3 -3
- classiq/applications/combinatorial_optimization/combinatorial_problem.py +4 -0
- classiq/applications/hamiltonian/pauli_decomposition.py +34 -2
- classiq/evaluators/argument_types.py +15 -6
- classiq/evaluators/parameter_types.py +43 -39
- classiq/evaluators/qmod_annotated_expression.py +117 -17
- classiq/evaluators/qmod_expression_visitors/out_of_place_node_transformer.py +19 -0
- classiq/evaluators/qmod_expression_visitors/qmod_expression_bwc.py +0 -5
- classiq/evaluators/qmod_expression_visitors/qmod_expression_evaluator.py +66 -16
- classiq/evaluators/qmod_expression_visitors/qmod_expression_renamer.py +48 -26
- classiq/evaluators/qmod_expression_visitors/qmod_expression_simplifier.py +65 -72
- classiq/evaluators/qmod_node_evaluators/attribute_evaluation.py +13 -6
- classiq/evaluators/qmod_node_evaluators/binary_op_evaluation.py +175 -28
- classiq/evaluators/qmod_node_evaluators/classical_function_evaluation.py +36 -19
- classiq/evaluators/qmod_node_evaluators/compare_evaluation.py +17 -5
- classiq/evaluators/qmod_node_evaluators/constant_evaluation.py +24 -2
- classiq/evaluators/qmod_node_evaluators/min_max_evaluation.py +97 -0
- classiq/evaluators/qmod_node_evaluators/name_evaluation.py +11 -26
- classiq/evaluators/qmod_node_evaluators/numeric_attrs_utils.py +56 -0
- classiq/evaluators/qmod_node_evaluators/piecewise_evaluation.py +40 -0
- classiq/evaluators/qmod_node_evaluators/struct_instantiation_evaluation.py +3 -4
- classiq/evaluators/qmod_node_evaluators/subscript_evaluation.py +51 -24
- classiq/evaluators/qmod_node_evaluators/unary_op_evaluation.py +53 -9
- classiq/evaluators/qmod_node_evaluators/utils.py +28 -6
- classiq/evaluators/qmod_type_inference/classical_type_inference.py +188 -0
- classiq/evaluators/qmod_type_inference/quantum_type_inference.py +330 -0
- classiq/evaluators/quantum_type_utils.py +0 -131
- classiq/evaluators/type_type_match.py +1 -1
- classiq/execution/execution_session.py +18 -3
- classiq/execution/qnn.py +4 -1
- classiq/execution/user_budgets.py +1 -1
- classiq/interface/_version.py +1 -1
- classiq/interface/backend/backend_preferences.py +10 -30
- classiq/interface/backend/quantum_backend_providers.py +63 -52
- classiq/interface/execution/primitives.py +1 -0
- classiq/interface/generator/application_apis/__init__.py +0 -1
- classiq/interface/generator/arith/binary_ops.py +107 -115
- classiq/interface/generator/arith/extremum_operations.py +33 -45
- classiq/interface/generator/arith/number_utils.py +4 -1
- classiq/interface/generator/circuit_code/types_and_constants.py +0 -9
- classiq/interface/generator/compiler_keywords.py +2 -0
- classiq/interface/generator/expressions/atomic_expression_functions.py +0 -2
- classiq/interface/generator/function_param_list.py +129 -5
- classiq/interface/generator/functions/classical_type.py +67 -2
- classiq/interface/generator/functions/qmod_python_interface.py +15 -0
- classiq/interface/generator/functions/type_name.py +12 -0
- classiq/interface/generator/model/preferences/preferences.py +1 -17
- classiq/interface/generator/quantum_program.py +1 -13
- classiq/interface/generator/transpiler_basis_gates.py +5 -1
- classiq/interface/generator/types/builtin_enum_declarations.py +0 -8
- classiq/interface/helpers/model_normalizer.py +2 -2
- classiq/interface/helpers/text_utils.py +7 -2
- classiq/interface/interface_version.py +1 -1
- classiq/interface/model/classical_if.py +48 -0
- classiq/interface/model/classical_parameter_declaration.py +4 -0
- classiq/interface/model/handle_binding.py +28 -16
- classiq/interface/model/port_declaration.py +12 -0
- classiq/interface/model/quantum_function_declaration.py +12 -0
- classiq/interface/model/quantum_type.py +117 -2
- classiq/interface/pretty_print/expression_to_qmod.py +7 -8
- classiq/interface/pyomo_extension/__init__.py +0 -4
- classiq/interface/pyomo_extension/pyomo_sympy_bimap.py +2 -2
- classiq/model_expansions/arithmetic.py +43 -1
- classiq/model_expansions/arithmetic_compute_result_attrs.py +255 -0
- classiq/model_expansions/capturing/captured_vars.py +2 -5
- classiq/model_expansions/quantum_operations/allocate.py +23 -16
- classiq/model_expansions/quantum_operations/arithmetic/explicit_boolean_expressions.py +1 -3
- classiq/model_expansions/quantum_operations/assignment_result_processor.py +52 -71
- classiq/model_expansions/quantum_operations/bind.py +15 -7
- classiq/model_expansions/quantum_operations/call_emitter.py +2 -10
- classiq/model_expansions/quantum_operations/classical_var_emitter.py +6 -0
- classiq/model_expansions/quantum_operations/handle_evaluator.py +2 -8
- classiq/open_library/functions/__init__.py +4 -0
- classiq/open_library/functions/lcu.py +117 -0
- 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 +26 -20
- classiq/qmod/builtins/functions/__init__.py +0 -5
- classiq/qmod/builtins/operations.py +142 -0
- classiq/qmod/builtins/structs.py +33 -29
- classiq/qmod/native/pretty_printer.py +1 -1
- classiq/qmod/pretty_print/expression_to_python.py +1 -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.86.1.dist-info → classiq-0.88.0.dist-info}/METADATA +5 -5
- {classiq-0.86.1.dist-info → classiq-0.88.0.dist-info}/RECORD +106 -124
- classiq/applications/finance/__init__.py +0 -15
- 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/amplitude_estimation.py +0 -34
- 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/interface/generator/function_param_list_without_self_reference.py +0 -160
- classiq/interface/generator/grover_diffuser.py +0 -93
- classiq/interface/generator/grover_operator.py +0 -106
- classiq/interface/generator/oracles/__init__.py +0 -3
- classiq/interface/generator/oracles/arithmetic_oracle.py +0 -82
- classiq/interface/generator/oracles/custom_oracle.py +0 -65
- classiq/interface/generator/oracles/oracle_abc.py +0 -76
- classiq/interface/generator/oracles/oracle_function_param_list.py +0 -6
- classiq/interface/generator/piecewise_linear_amplitude_loading.py +0 -165
- classiq/interface/generator/qpe.py +0 -169
- classiq/interface/grover/__init__.py +0 -0
- classiq/interface/grover/grover_modelling_params.py +0 -13
- classiq/model_expansions/transformers/var_splitter.py +0 -224
- classiq/qmod/builtins/functions/finance.py +0 -34
- /classiq/{interface/finance → evaluators/qmod_type_inference}/__init__.py +0 -0
- {classiq-0.86.1.dist-info → classiq-0.88.0.dist-info}/WHEEL +0 -0
|
@@ -28,10 +28,14 @@ from classiq.evaluators.qmod_node_evaluators.utils import (
|
|
|
28
28
|
QmodType,
|
|
29
29
|
array_len,
|
|
30
30
|
element_types,
|
|
31
|
-
|
|
31
|
+
is_classical_integer,
|
|
32
|
+
)
|
|
33
|
+
from classiq.evaluators.qmod_type_inference.classical_type_inference import (
|
|
34
|
+
infer_classical_type,
|
|
32
35
|
)
|
|
33
36
|
|
|
34
|
-
|
|
37
|
+
# These sympy functions are not declared as int funcs for some reason...
|
|
38
|
+
INTEGER_FUNCTION_OVERRIDE = {"floor", "ceiling"}
|
|
35
39
|
|
|
36
40
|
|
|
37
41
|
def _check_classical_array_arg_type(
|
|
@@ -91,8 +95,8 @@ def _check_classical_arg(
|
|
|
91
95
|
):
|
|
92
96
|
raise ClassiqExpansionError(
|
|
93
97
|
f"Parameter {param_name!r} of function {func_name!r} expects a "
|
|
94
|
-
f"{
|
|
95
|
-
f"{
|
|
98
|
+
f"{param_type.qmod_type_name} argument, but got a "
|
|
99
|
+
f"{arg_type.qmod_type_name}"
|
|
96
100
|
)
|
|
97
101
|
|
|
98
102
|
|
|
@@ -168,7 +172,9 @@ def eval_function(
|
|
|
168
172
|
cast(str, kwarg_name): expr_val.get_value(kwarg_value)
|
|
169
173
|
for kwarg_name, kwarg_value in kwargs.items()
|
|
170
174
|
}
|
|
171
|
-
|
|
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)
|
|
172
178
|
|
|
173
179
|
|
|
174
180
|
def try_eval_sympy_function(
|
|
@@ -191,7 +197,9 @@ def try_eval_sympy_function(
|
|
|
191
197
|
ret_type = Bool()
|
|
192
198
|
if args is not None:
|
|
193
199
|
ret_val = bool(sympy_ret_val)
|
|
194
|
-
elif
|
|
200
|
+
elif (
|
|
201
|
+
hasattr(sympy_func, "is_Integer") and sympy_func.is_Integer
|
|
202
|
+
) or func_name in INTEGER_FUNCTION_OVERRIDE:
|
|
195
203
|
ret_type = Integer()
|
|
196
204
|
if args is not None:
|
|
197
205
|
ret_val = int(sympy_ret_val)
|
|
@@ -241,15 +249,6 @@ def try_eval_builtin_function(
|
|
|
241
249
|
)
|
|
242
250
|
args_have_values = all(expr_val.has_value(arg) for arg in node.args)
|
|
243
251
|
|
|
244
|
-
if func_name in MIN_MAX_FUNCTION_NAMES:
|
|
245
|
-
if not try_eval_sympy_function(expr_val, node, func_name.capitalize()):
|
|
246
|
-
return False
|
|
247
|
-
if args_are_int:
|
|
248
|
-
expr_val.set_type(node, Integer())
|
|
249
|
-
if expr_val.has_value(node):
|
|
250
|
-
expr_val.set_value(node, int(expr_val.get_value(node)))
|
|
251
|
-
return True
|
|
252
|
-
|
|
253
252
|
if func_name == "mod_inverse":
|
|
254
253
|
_validate_no_kwargs(node)
|
|
255
254
|
ret_type: QmodType
|
|
@@ -267,10 +266,10 @@ def try_eval_builtin_function(
|
|
|
267
266
|
*[expr_val.get_value(arg) for arg in node.args]
|
|
268
267
|
)
|
|
269
268
|
ret_val: Any
|
|
270
|
-
if
|
|
271
|
-
ret_val = int(sympy_val)
|
|
272
|
-
elif isinstance(sympy_val, sympy.Expr) and sympy_val.is_imaginary:
|
|
269
|
+
if isinstance(sympy_val, sympy.Expr) and sympy_val.is_imaginary:
|
|
273
270
|
ret_val = complex(sympy_val)
|
|
271
|
+
elif args_are_int:
|
|
272
|
+
ret_val = int(sympy_val)
|
|
274
273
|
else:
|
|
275
274
|
ret_val = float(sympy_val)
|
|
276
275
|
expr_val.set_value(node, ret_val)
|
|
@@ -292,9 +291,27 @@ def try_eval_builtin_function(
|
|
|
292
291
|
if func_name == "sqrt":
|
|
293
292
|
_validate_no_kwargs(node)
|
|
294
293
|
expr_val.set_type(node, Real())
|
|
294
|
+
if args_have_values:
|
|
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)
|
|
303
|
+
return True
|
|
304
|
+
|
|
305
|
+
if func_name == "abs":
|
|
306
|
+
_validate_no_kwargs(node)
|
|
307
|
+
if len(node.args) > 0 and is_classical_integer(expr_val.get_type(node.args[0])):
|
|
308
|
+
ret_type = Integer()
|
|
309
|
+
else:
|
|
310
|
+
ret_type = Real()
|
|
311
|
+
expr_val.set_type(node, ret_type)
|
|
295
312
|
if args_have_values:
|
|
296
313
|
expr_val.set_value(
|
|
297
|
-
node,
|
|
314
|
+
node, abs(*[expr_val.get_value(arg) for arg in node.args])
|
|
298
315
|
)
|
|
299
316
|
return True
|
|
300
317
|
|
|
@@ -14,6 +14,7 @@ from classiq.interface.generator.functions.classical_type import (
|
|
|
14
14
|
from classiq.interface.generator.functions.type_name import TypeName
|
|
15
15
|
from classiq.interface.model.quantum_type import (
|
|
16
16
|
QuantumBit,
|
|
17
|
+
QuantumBitvector,
|
|
17
18
|
QuantumNumeric,
|
|
18
19
|
QuantumScalar,
|
|
19
20
|
)
|
|
@@ -23,7 +24,6 @@ from classiq.evaluators.qmod_node_evaluators.list_evaluation import list_allowed
|
|
|
23
24
|
from classiq.evaluators.qmod_node_evaluators.utils import (
|
|
24
25
|
QmodType,
|
|
25
26
|
element_types,
|
|
26
|
-
get_qmod_type_name,
|
|
27
27
|
is_classical_integer,
|
|
28
28
|
is_classical_type,
|
|
29
29
|
qnum_is_qbit,
|
|
@@ -34,11 +34,13 @@ def comparison_allowed(
|
|
|
34
34
|
left: QmodType, right: QmodType, inequality: bool = False
|
|
35
35
|
) -> bool:
|
|
36
36
|
if isinstance(left, Bool):
|
|
37
|
-
return isinstance(right, (Bool, QuantumBit)) or (
|
|
37
|
+
return isinstance(right, (Bool, Integer, QuantumBit)) or (
|
|
38
38
|
isinstance(right, QuantumNumeric) and qnum_is_qbit(right)
|
|
39
39
|
)
|
|
40
40
|
if isinstance(left, Real) or is_classical_integer(left):
|
|
41
|
-
return isinstance(right, (Real, QuantumScalar)) or is_classical_integer(
|
|
41
|
+
return isinstance(right, (Real, Bool, QuantumScalar)) or is_classical_integer(
|
|
42
|
+
right
|
|
43
|
+
)
|
|
42
44
|
if isinstance(left, (ClassicalArray, ClassicalTuple)):
|
|
43
45
|
if inequality:
|
|
44
46
|
return False
|
|
@@ -62,6 +64,8 @@ def comparison_allowed(
|
|
|
62
64
|
return isinstance(right, (Bool, Real, QuantumScalar)) or is_classical_integer(
|
|
63
65
|
right
|
|
64
66
|
)
|
|
67
|
+
if isinstance(left, QuantumBitvector):
|
|
68
|
+
return False
|
|
65
69
|
raise ClassiqInternalExpansionError
|
|
66
70
|
|
|
67
71
|
|
|
@@ -76,8 +80,8 @@ def eval_compare(expr_val: QmodAnnotatedExpression, node: ast.Compare) -> None:
|
|
|
76
80
|
right_type = expr_val.get_type(right)
|
|
77
81
|
if not comparison_allowed(left_type, right_type, not isinstance(op, ast.Eq)):
|
|
78
82
|
raise ClassiqExpansionError(
|
|
79
|
-
f"Cannot compare {
|
|
80
|
-
f"and {
|
|
83
|
+
f"Cannot compare {left_type.qmod_type_name} {ast.unparse(left)!r} "
|
|
84
|
+
f"and {right_type.qmod_type_name} {ast.unparse(right)!r}"
|
|
81
85
|
)
|
|
82
86
|
qmod_type: QmodType
|
|
83
87
|
if not is_classical_type(left_type) or not is_classical_type(right_type):
|
|
@@ -96,12 +100,20 @@ def eval_compare(expr_val: QmodAnnotatedExpression, node: ast.Compare) -> None:
|
|
|
96
100
|
elif isinstance(op, ast.NotEq):
|
|
97
101
|
expr_val.set_value(node, left_value != right_value)
|
|
98
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")
|
|
99
105
|
expr_val.set_value(node, left_value < right_value)
|
|
100
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")
|
|
101
109
|
expr_val.set_value(node, left_value > right_value)
|
|
102
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")
|
|
103
113
|
expr_val.set_value(node, left_value <= right_value)
|
|
104
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")
|
|
105
117
|
expr_val.set_value(node, left_value >= right_value)
|
|
106
118
|
else:
|
|
107
119
|
raise ClassiqExpansionError(f"Unsupported comparison {type(op).__name__!r}")
|
|
@@ -7,12 +7,22 @@ import sympy
|
|
|
7
7
|
from classiq.interface.exceptions import (
|
|
8
8
|
ClassiqExpansionError,
|
|
9
9
|
)
|
|
10
|
-
from classiq.interface.generator.functions.classical_type import
|
|
10
|
+
from classiq.interface.generator.functions.classical_type import (
|
|
11
|
+
Bool,
|
|
12
|
+
ClassicalType,
|
|
13
|
+
Integer,
|
|
14
|
+
Real,
|
|
15
|
+
)
|
|
11
16
|
from classiq.interface.generator.functions.type_name import Enum
|
|
12
17
|
|
|
13
18
|
from classiq.evaluators.qmod_annotated_expression import QmodAnnotatedExpression
|
|
14
19
|
from classiq.evaluators.qmod_node_evaluators.utils import SYMPY_SYMBOLS, QmodType
|
|
15
20
|
|
|
21
|
+
QMOD_LITERALS: dict[str, tuple[ClassicalType, Any]] = {
|
|
22
|
+
"false": (Bool(), False),
|
|
23
|
+
"true": (Bool(), True),
|
|
24
|
+
}
|
|
25
|
+
|
|
16
26
|
|
|
17
27
|
def eval_enum_member(
|
|
18
28
|
expr_val: QmodAnnotatedExpression, node: ast.Attribute, enum: type[IntEnum]
|
|
@@ -23,7 +33,10 @@ def eval_enum_member(
|
|
|
23
33
|
}
|
|
24
34
|
attr = node.attr
|
|
25
35
|
if attr not in enum_members:
|
|
26
|
-
raise ClassiqExpansionError(
|
|
36
|
+
raise ClassiqExpansionError(
|
|
37
|
+
f"Enum {enum_name} has no member {attr!r}. Available members: "
|
|
38
|
+
f"{', '.join(enum_members.keys())}"
|
|
39
|
+
)
|
|
27
40
|
|
|
28
41
|
expr_val.set_type(node, Enum(name=enum_name))
|
|
29
42
|
expr_val.set_value(node, enum_members[attr])
|
|
@@ -44,6 +57,15 @@ def eval_constant(expr_val: QmodAnnotatedExpression, node: ast.Constant) -> None
|
|
|
44
57
|
expr_val.set_type(node, constant_type)
|
|
45
58
|
|
|
46
59
|
|
|
60
|
+
def try_eval_qmod_literal(expr_val: QmodAnnotatedExpression, node: ast.Name) -> bool:
|
|
61
|
+
if node.id not in QMOD_LITERALS:
|
|
62
|
+
return False
|
|
63
|
+
lit_type, lit_val = QMOD_LITERALS[node.id]
|
|
64
|
+
expr_val.set_type(node, lit_type)
|
|
65
|
+
expr_val.set_value(node, lit_val)
|
|
66
|
+
return True
|
|
67
|
+
|
|
68
|
+
|
|
47
69
|
def try_eval_sympy_constant(expr_val: QmodAnnotatedExpression, node: ast.Name) -> bool:
|
|
48
70
|
sympy_val = SYMPY_SYMBOLS.get(node.id)
|
|
49
71
|
if not isinstance(sympy_val, sympy.Expr) or not sympy_val.is_constant():
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
import ast
|
|
2
|
+
|
|
3
|
+
from classiq.interface.exceptions import (
|
|
4
|
+
ClassiqExpansionError,
|
|
5
|
+
ClassiqInternalExpansionError,
|
|
6
|
+
)
|
|
7
|
+
from classiq.interface.generator.functions.classical_type import Integer, Real
|
|
8
|
+
from classiq.interface.model.quantum_type import QuantumNumeric
|
|
9
|
+
|
|
10
|
+
from classiq.evaluators.qmod_annotated_expression import QmodAnnotatedExpression
|
|
11
|
+
from classiq.evaluators.qmod_node_evaluators.numeric_attrs_utils import (
|
|
12
|
+
get_numeric_attrs,
|
|
13
|
+
)
|
|
14
|
+
from classiq.evaluators.qmod_node_evaluators.utils import (
|
|
15
|
+
QmodType,
|
|
16
|
+
is_classical_integer,
|
|
17
|
+
is_classical_type,
|
|
18
|
+
is_numeric_type,
|
|
19
|
+
)
|
|
20
|
+
from classiq.model_expansions.arithmetic import NumericAttributes
|
|
21
|
+
from classiq.model_expansions.arithmetic_compute_result_attrs import (
|
|
22
|
+
compute_result_attrs_max,
|
|
23
|
+
compute_result_attrs_min,
|
|
24
|
+
)
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
def _infer_min_max_op_type(
|
|
28
|
+
expr_val: QmodAnnotatedExpression,
|
|
29
|
+
node: ast.Call,
|
|
30
|
+
func_name: str,
|
|
31
|
+
args_types: list[QmodType],
|
|
32
|
+
treat_qnum_as_float: bool,
|
|
33
|
+
machine_precision: int,
|
|
34
|
+
) -> QmodType:
|
|
35
|
+
if all(is_classical_type(arg_type) for arg_type in args_types):
|
|
36
|
+
if all(is_classical_integer(arg_type) for arg_type in args_types):
|
|
37
|
+
return Integer()
|
|
38
|
+
return Real()
|
|
39
|
+
|
|
40
|
+
args_attrs: list[NumericAttributes] = []
|
|
41
|
+
for arg, arg_type in zip(node.args, args_types):
|
|
42
|
+
attrs = get_numeric_attrs(
|
|
43
|
+
expr_val, arg, arg_type, machine_precision, treat_qnum_as_float
|
|
44
|
+
)
|
|
45
|
+
if attrs is None:
|
|
46
|
+
return QuantumNumeric()
|
|
47
|
+
args_attrs.append(attrs)
|
|
48
|
+
|
|
49
|
+
if func_name == "min":
|
|
50
|
+
result_attrs = compute_result_attrs_min(args_attrs, machine_precision)
|
|
51
|
+
elif func_name == "max":
|
|
52
|
+
result_attrs = compute_result_attrs_max(args_attrs, machine_precision)
|
|
53
|
+
else:
|
|
54
|
+
raise ClassiqInternalExpansionError
|
|
55
|
+
|
|
56
|
+
return result_attrs.to_quantum_numeric()
|
|
57
|
+
|
|
58
|
+
|
|
59
|
+
def eval_min_max_op(
|
|
60
|
+
expr_val: QmodAnnotatedExpression,
|
|
61
|
+
node: ast.Call,
|
|
62
|
+
func_name: str,
|
|
63
|
+
treat_qnum_as_float: bool,
|
|
64
|
+
machine_precision: int,
|
|
65
|
+
) -> None:
|
|
66
|
+
if len(node.args) < 1:
|
|
67
|
+
raise ClassiqExpansionError(f"{func_name!r} expects at least one argument")
|
|
68
|
+
|
|
69
|
+
args_types = [expr_val.get_type(arg) for arg in node.args]
|
|
70
|
+
if not all(is_numeric_type(arg_type) for arg_type in args_types):
|
|
71
|
+
raise ClassiqExpansionError(
|
|
72
|
+
f"All arguments of {func_name!r} must be scalar values"
|
|
73
|
+
)
|
|
74
|
+
|
|
75
|
+
inferred_type = _infer_min_max_op_type(
|
|
76
|
+
expr_val,
|
|
77
|
+
node,
|
|
78
|
+
func_name,
|
|
79
|
+
args_types,
|
|
80
|
+
treat_qnum_as_float,
|
|
81
|
+
machine_precision,
|
|
82
|
+
)
|
|
83
|
+
expr_val.set_type(node, inferred_type)
|
|
84
|
+
|
|
85
|
+
if all(expr_val.has_value(arg) for arg in node.args):
|
|
86
|
+
values = [expr_val.get_value(arg) for arg in node.args]
|
|
87
|
+
if not all(isinstance(value, (int, float)) for value in values):
|
|
88
|
+
raise ClassiqExpansionError(f"Invalid argument for function {func_name!r}")
|
|
89
|
+
|
|
90
|
+
if func_name == "min":
|
|
91
|
+
result_value = min(*values)
|
|
92
|
+
elif func_name == "max":
|
|
93
|
+
result_value = max(*values)
|
|
94
|
+
else:
|
|
95
|
+
raise ClassiqInternalExpansionError
|
|
96
|
+
|
|
97
|
+
expr_val.set_value(node, result_value)
|
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
import ast
|
|
2
2
|
from typing import Any
|
|
3
3
|
|
|
4
|
+
import sympy
|
|
5
|
+
|
|
4
6
|
from classiq.interface.exceptions import (
|
|
5
7
|
ClassiqInternalExpansionError,
|
|
6
8
|
)
|
|
@@ -8,42 +10,25 @@ from classiq.interface.generator.expressions.proxies.classical.qmod_struct_insta
|
|
|
8
10
|
QmodStructInstance,
|
|
9
11
|
)
|
|
10
12
|
from classiq.interface.generator.functions.classical_type import (
|
|
11
|
-
Bool,
|
|
12
|
-
ClassicalTuple,
|
|
13
13
|
ClassicalType,
|
|
14
|
-
Integer,
|
|
15
|
-
Real,
|
|
16
14
|
)
|
|
17
|
-
from classiq.interface.generator.functions.type_name import Struct
|
|
18
15
|
from classiq.interface.model.handle_binding import HandleBinding
|
|
19
16
|
from classiq.interface.model.quantum_type import QuantumType
|
|
20
17
|
|
|
21
18
|
from classiq.evaluators.qmod_annotated_expression import QmodAnnotatedExpression
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
if isinstance(value, bool):
|
|
26
|
-
return Bool()
|
|
27
|
-
if isinstance(value, int):
|
|
28
|
-
return Integer()
|
|
29
|
-
if isinstance(value, (float, complex)):
|
|
30
|
-
return Real()
|
|
31
|
-
if isinstance(value, list):
|
|
32
|
-
return ClassicalTuple(
|
|
33
|
-
element_types=[_infer_classical_type(item) for item in value]
|
|
34
|
-
)
|
|
35
|
-
if isinstance(value, QmodStructInstance):
|
|
36
|
-
classical_type = Struct(name=value.struct_declaration.name)
|
|
37
|
-
classical_type.set_classical_struct_decl(value.struct_declaration)
|
|
38
|
-
return classical_type
|
|
39
|
-
raise ClassiqInternalExpansionError
|
|
19
|
+
from classiq.evaluators.qmod_type_inference.classical_type_inference import (
|
|
20
|
+
infer_classical_type,
|
|
21
|
+
)
|
|
40
22
|
|
|
41
23
|
|
|
42
24
|
def eval_name(expr_val: QmodAnnotatedExpression, node: ast.Name, value: Any) -> None:
|
|
43
|
-
|
|
44
|
-
|
|
25
|
+
# FIXME: Remove sympy compatibility (CLS-3214)
|
|
26
|
+
if isinstance(
|
|
27
|
+
value, (bool, int, float, complex, list, QmodStructInstance, sympy.Basic)
|
|
28
|
+
):
|
|
29
|
+
expr_val.set_type(node, infer_classical_type(value))
|
|
45
30
|
expr_val.set_value(node, value)
|
|
46
|
-
elif isinstance(value, (ClassicalType, QuantumType)):
|
|
31
|
+
elif isinstance(value, (ClassicalType, QuantumType)): # type:ignore[unreachable]
|
|
47
32
|
expr_val.set_type(node, value)
|
|
48
33
|
expr_val.set_var(node, HandleBinding(name=node.id))
|
|
49
34
|
else:
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
import ast
|
|
2
|
+
from typing import TYPE_CHECKING, Optional
|
|
3
|
+
|
|
4
|
+
from classiq.interface.exceptions import ClassiqExpansionError
|
|
5
|
+
from classiq.interface.generator.functions.classical_type import Bool
|
|
6
|
+
from classiq.interface.model.quantum_type import QuantumScalar
|
|
7
|
+
|
|
8
|
+
from classiq.evaluators.qmod_annotated_expression import QmodAnnotatedExpression
|
|
9
|
+
from classiq.evaluators.qmod_node_evaluators.utils import QmodType, is_classical_type
|
|
10
|
+
from classiq.model_expansions.arithmetic import NumericAttributes
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
def get_numeric_attrs(
|
|
14
|
+
expr_val: QmodAnnotatedExpression,
|
|
15
|
+
node: ast.AST,
|
|
16
|
+
qmod_type: QmodType,
|
|
17
|
+
machine_precision: int,
|
|
18
|
+
treat_qnum_as_float: bool,
|
|
19
|
+
) -> Optional[NumericAttributes]:
|
|
20
|
+
if isinstance(qmod_type, Bool):
|
|
21
|
+
return NumericAttributes.from_bounds(0, 1, 0, machine_precision)
|
|
22
|
+
if is_classical_type(qmod_type):
|
|
23
|
+
value = get_classical_value_for_arithmetic(
|
|
24
|
+
expr_val, node, qmod_type, treat_qnum_as_float
|
|
25
|
+
)
|
|
26
|
+
if value is None:
|
|
27
|
+
return None
|
|
28
|
+
return NumericAttributes.from_constant(value, machine_precision)
|
|
29
|
+
|
|
30
|
+
if TYPE_CHECKING:
|
|
31
|
+
assert isinstance(qmod_type, QuantumScalar)
|
|
32
|
+
if not qmod_type.is_constant:
|
|
33
|
+
return None
|
|
34
|
+
return NumericAttributes.from_quantum_scalar(qmod_type, machine_precision)
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
def get_classical_value_for_arithmetic(
|
|
38
|
+
expr_val: QmodAnnotatedExpression,
|
|
39
|
+
node: ast.AST,
|
|
40
|
+
qmod_type: QmodType,
|
|
41
|
+
treat_qnum_as_float: bool,
|
|
42
|
+
) -> Optional[float]:
|
|
43
|
+
if not is_classical_type(qmod_type):
|
|
44
|
+
return None
|
|
45
|
+
if not expr_val.has_value(node):
|
|
46
|
+
return None
|
|
47
|
+
|
|
48
|
+
value = expr_val.get_value(node)
|
|
49
|
+
if not isinstance(value, (int, float)):
|
|
50
|
+
if treat_qnum_as_float and isinstance(value, complex):
|
|
51
|
+
return None
|
|
52
|
+
raise ClassiqExpansionError(
|
|
53
|
+
"Arithmetic of quantum variables and non-real values is not supported"
|
|
54
|
+
)
|
|
55
|
+
|
|
56
|
+
return float(value)
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import ast
|
|
2
|
+
from collections.abc import Sequence
|
|
3
|
+
|
|
4
|
+
import sympy
|
|
5
|
+
|
|
6
|
+
from classiq.interface.exceptions import ClassiqExpansionError
|
|
7
|
+
from classiq.interface.generator.functions.classical_type import Bool, Integer, Real
|
|
8
|
+
|
|
9
|
+
from classiq.evaluators.qmod_annotated_expression import QmodAnnotatedExpression
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
def eval_piecewise(
|
|
13
|
+
expr_val: QmodAnnotatedExpression,
|
|
14
|
+
node: ast.Call,
|
|
15
|
+
args: Sequence[tuple[ast.AST, ast.AST]],
|
|
16
|
+
) -> None:
|
|
17
|
+
cond_types = [expr_val.get_type(cond) for _, cond in args]
|
|
18
|
+
if not all(isinstance(cond_type, Bool) for cond_type in cond_types):
|
|
19
|
+
raise ClassiqExpansionError(
|
|
20
|
+
"Piecewise conditions must be classical Boolean values"
|
|
21
|
+
)
|
|
22
|
+
|
|
23
|
+
value_types = [expr_val.get_type(value) for value, _ in args]
|
|
24
|
+
if not all(isinstance(value_type, (Integer, Real)) for value_type in value_types):
|
|
25
|
+
raise ClassiqExpansionError("Piecewise values must be classical numeric values")
|
|
26
|
+
|
|
27
|
+
if all(isinstance(value_type, Integer) for value_type in value_types):
|
|
28
|
+
expr_val.set_type(node, Integer())
|
|
29
|
+
else:
|
|
30
|
+
expr_val.set_type(node, Real())
|
|
31
|
+
|
|
32
|
+
if not all(
|
|
33
|
+
expr_val.has_value(value) and expr_val.has_value(cond) for value, cond in args
|
|
34
|
+
):
|
|
35
|
+
return
|
|
36
|
+
|
|
37
|
+
values = [
|
|
38
|
+
(expr_val.get_value(value), expr_val.get_value(cond)) for value, cond in args
|
|
39
|
+
]
|
|
40
|
+
expr_val.set_value(node, sympy.Piecewise(*values))
|
|
@@ -15,13 +15,12 @@ from classiq.evaluators.qmod_annotated_expression import QmodAnnotatedExpression
|
|
|
15
15
|
from classiq.evaluators.qmod_node_evaluators.compare_evaluation import (
|
|
16
16
|
comparison_allowed,
|
|
17
17
|
)
|
|
18
|
-
from classiq.evaluators.qmod_node_evaluators.utils import get_qmod_type_name
|
|
19
18
|
|
|
20
19
|
|
|
21
20
|
def eval_struct_instantiation(
|
|
22
21
|
expr_val: QmodAnnotatedExpression, node: ast.Call, decl: StructDeclaration
|
|
23
22
|
) -> None:
|
|
24
|
-
if len(node.args)
|
|
23
|
+
if len(node.args) != 1 or any(kwarg.arg is None for kwarg in node.keywords):
|
|
25
24
|
raise ClassiqExpansionError(
|
|
26
25
|
"Classical structs must be instantiated using keyword arguments"
|
|
27
26
|
)
|
|
@@ -42,8 +41,8 @@ def eval_struct_instantiation(
|
|
|
42
41
|
expected_type = decl.variables[field_name]
|
|
43
42
|
if not comparison_allowed(assignment_type, expected_type):
|
|
44
43
|
raise ClassiqExpansionError(
|
|
45
|
-
f"Cannot assign value of type {
|
|
46
|
-
f"to field {field_name!r} of type {
|
|
44
|
+
f"Cannot assign value of type {assignment_type.qmod_type_name} "
|
|
45
|
+
f"to field {field_name!r} of type {expected_type.qmod_type_name}"
|
|
47
46
|
)
|
|
48
47
|
|
|
49
48
|
classical_type = Struct(name=decl.name)
|
|
@@ -4,10 +4,7 @@ from typing import Optional, cast
|
|
|
4
4
|
from classiq.interface.exceptions import (
|
|
5
5
|
ClassiqExpansionError,
|
|
6
6
|
ClassiqInternalExpansionError,
|
|
7
|
-
|
|
8
|
-
from classiq.interface.generator.arith.arithmetic import (
|
|
9
|
-
aggregate_numeric_types,
|
|
10
|
-
compute_arithmetic_result_type,
|
|
7
|
+
ClassiqValueError,
|
|
11
8
|
)
|
|
12
9
|
from classiq.interface.generator.expressions.expression import Expression
|
|
13
10
|
from classiq.interface.generator.functions.classical_type import (
|
|
@@ -16,6 +13,7 @@ from classiq.interface.generator.functions.classical_type import (
|
|
|
16
13
|
Integer,
|
|
17
14
|
Real,
|
|
18
15
|
)
|
|
16
|
+
from classiq.interface.helpers.text_utils import s
|
|
19
17
|
from classiq.interface.model.handle_binding import (
|
|
20
18
|
SlicedHandleBinding,
|
|
21
19
|
SubscriptHandleBinding,
|
|
@@ -23,16 +21,19 @@ from classiq.interface.model.handle_binding import (
|
|
|
23
21
|
from classiq.interface.model.quantum_type import (
|
|
24
22
|
QuantumBitvector,
|
|
25
23
|
QuantumNumeric,
|
|
24
|
+
QuantumScalar,
|
|
26
25
|
QuantumType,
|
|
27
|
-
register_info_to_quantum_type,
|
|
28
26
|
)
|
|
29
27
|
|
|
30
28
|
from classiq.evaluators.qmod_annotated_expression import QmodAnnotatedExpression
|
|
31
29
|
from classiq.evaluators.qmod_node_evaluators.utils import (
|
|
32
30
|
QmodType,
|
|
31
|
+
array_len,
|
|
33
32
|
element_types,
|
|
34
|
-
|
|
35
|
-
|
|
33
|
+
get_numeric_properties,
|
|
34
|
+
)
|
|
35
|
+
from classiq.model_expansions.arithmetic_compute_result_attrs import (
|
|
36
|
+
compute_result_attrs_quantum_subscript,
|
|
36
37
|
)
|
|
37
38
|
|
|
38
39
|
|
|
@@ -49,7 +50,7 @@ def _eval_slice(expr_val: QmodAnnotatedExpression, node: ast.Subscript) -> None:
|
|
|
49
50
|
for index_type in (start_type, stop_type):
|
|
50
51
|
if not isinstance(index_type, Integer):
|
|
51
52
|
raise ClassiqExpansionError(
|
|
52
|
-
f"Slice indices must be integers, not {
|
|
53
|
+
f"Slice indices must be integers, not {index_type.raw_qmod_type_name}"
|
|
53
54
|
)
|
|
54
55
|
|
|
55
56
|
start_val: Optional[int] = None
|
|
@@ -68,7 +69,7 @@ def _eval_slice(expr_val: QmodAnnotatedExpression, node: ast.Subscript) -> None:
|
|
|
68
69
|
subject_type = expr_val.get_type(subject)
|
|
69
70
|
slice_type: QmodType
|
|
70
71
|
if isinstance(subject_type, ClassicalArray):
|
|
71
|
-
if subject_type.
|
|
72
|
+
if subject_type.has_constant_length and (
|
|
72
73
|
(start_val is not None and start_val >= subject_type.length_value)
|
|
73
74
|
or (stop_val is not None and stop_val > subject_type.length_value)
|
|
74
75
|
):
|
|
@@ -92,7 +93,7 @@ def _eval_slice(expr_val: QmodAnnotatedExpression, node: ast.Subscript) -> None:
|
|
|
92
93
|
slice_type = subject_type.get_raw_type()
|
|
93
94
|
elif isinstance(subject_type, QuantumBitvector):
|
|
94
95
|
if start_val is not None and stop_val is not None:
|
|
95
|
-
if subject_type.
|
|
96
|
+
if subject_type.has_constant_length and (
|
|
96
97
|
start_val >= subject_type.length_value
|
|
97
98
|
or stop_val > subject_type.length_value
|
|
98
99
|
):
|
|
@@ -105,7 +106,7 @@ def _eval_slice(expr_val: QmodAnnotatedExpression, node: ast.Subscript) -> None:
|
|
|
105
106
|
)
|
|
106
107
|
else:
|
|
107
108
|
raise ClassiqExpansionError(
|
|
108
|
-
f"{
|
|
109
|
+
f"{subject_type.raw_qmod_type_name} is not subscriptable"
|
|
109
110
|
)
|
|
110
111
|
expr_val.set_type(node, slice_type)
|
|
111
112
|
|
|
@@ -134,7 +135,8 @@ def _eval_subscript(expr_val: QmodAnnotatedExpression, node: ast.Subscript) -> N
|
|
|
134
135
|
index_type = expr_val.get_type(subscript)
|
|
135
136
|
if not isinstance(index_type, Integer):
|
|
136
137
|
raise ClassiqExpansionError(
|
|
137
|
-
f"Array indices must be integers or slices, not
|
|
138
|
+
f"Array indices must be integers or slices, not "
|
|
139
|
+
f"{index_type.raw_qmod_type_name}"
|
|
138
140
|
)
|
|
139
141
|
|
|
140
142
|
sub_val: Optional[int] = None
|
|
@@ -148,7 +150,7 @@ def _eval_subscript(expr_val: QmodAnnotatedExpression, node: ast.Subscript) -> N
|
|
|
148
150
|
if isinstance(subject_type, (ClassicalArray, QuantumBitvector)):
|
|
149
151
|
if (
|
|
150
152
|
sub_val is not None
|
|
151
|
-
and subject_type.
|
|
153
|
+
and subject_type.has_constant_length
|
|
152
154
|
and sub_val >= subject_type.length_value
|
|
153
155
|
):
|
|
154
156
|
raise ClassiqExpansionError("Array index out of range")
|
|
@@ -165,7 +167,7 @@ def _eval_subscript(expr_val: QmodAnnotatedExpression, node: ast.Subscript) -> N
|
|
|
165
167
|
sub_type = raw_subject_type.element_type
|
|
166
168
|
else:
|
|
167
169
|
raise ClassiqExpansionError(
|
|
168
|
-
f"{
|
|
170
|
+
f"{subject_type.raw_qmod_type_name} is not subscriptable"
|
|
169
171
|
)
|
|
170
172
|
expr_val.set_type(node, sub_type)
|
|
171
173
|
|
|
@@ -192,15 +194,38 @@ def eval_subscript(expr_val: QmodAnnotatedExpression, node: ast.Subscript) -> No
|
|
|
192
194
|
_eval_subscript(expr_val, node)
|
|
193
195
|
|
|
194
196
|
|
|
197
|
+
def validate_quantum_subscript_index_properties(
|
|
198
|
+
index_size: Optional[int],
|
|
199
|
+
index_sign: Optional[bool],
|
|
200
|
+
index_fraction_digits: Optional[int],
|
|
201
|
+
array_len: Optional[int],
|
|
202
|
+
) -> None:
|
|
203
|
+
if index_sign or (index_fraction_digits is not None and index_fraction_digits > 0):
|
|
204
|
+
raise ClassiqValueError("Quantum index must be an unsigned integer")
|
|
205
|
+
if array_len == 0:
|
|
206
|
+
raise ClassiqValueError(
|
|
207
|
+
"Classical arrays indexed by a quantum variable must not be empty"
|
|
208
|
+
)
|
|
209
|
+
if array_len is None or index_size is None:
|
|
210
|
+
return
|
|
211
|
+
if 2**index_size > array_len:
|
|
212
|
+
adjective = "short"
|
|
213
|
+
elif 2**index_size < array_len:
|
|
214
|
+
adjective = "long"
|
|
215
|
+
else:
|
|
216
|
+
return
|
|
217
|
+
raise ClassiqValueError(
|
|
218
|
+
f"Array is too {adjective}. It has {array_len} item{s(array_len)}, but its "
|
|
219
|
+
f"quantum index has {index_size} bit{s(index_size)}"
|
|
220
|
+
)
|
|
221
|
+
|
|
222
|
+
|
|
195
223
|
def eval_quantum_subscript(
|
|
196
224
|
expr_val: QmodAnnotatedExpression, node: ast.Subscript, machine_precision: int
|
|
197
225
|
) -> None:
|
|
198
226
|
subject = node.value
|
|
199
227
|
subscript = node.slice
|
|
200
228
|
|
|
201
|
-
index_type = cast(QuantumType, expr_val.get_type(subscript))
|
|
202
|
-
if not qnum_is_qint(index_type):
|
|
203
|
-
raise ClassiqExpansionError("Quantum indices must be unsigned quantum numerics")
|
|
204
229
|
subject_type = expr_val.get_type(subject)
|
|
205
230
|
if not isinstance(subject_type, (ClassicalArray, ClassicalTuple)) or not all(
|
|
206
231
|
isinstance(element_type, (Integer, Real))
|
|
@@ -210,16 +235,18 @@ def eval_quantum_subscript(
|
|
|
210
235
|
"Only classical numeric arrays may have quantum subscripts"
|
|
211
236
|
)
|
|
212
237
|
|
|
238
|
+
index_type = cast(QuantumType, expr_val.get_type(subscript))
|
|
239
|
+
if not isinstance(index_type, QuantumScalar):
|
|
240
|
+
raise ClassiqExpansionError("Quantum index must be an unsigned integer")
|
|
241
|
+
validate_quantum_subscript_index_properties(
|
|
242
|
+
*get_numeric_properties(index_type), array_len(subject_type)
|
|
243
|
+
)
|
|
244
|
+
|
|
213
245
|
expr_val.set_quantum_subscript(node, subject, subscript)
|
|
214
246
|
if not expr_val.has_value(subject):
|
|
215
247
|
expr_val.set_type(node, QuantumNumeric())
|
|
216
248
|
return
|
|
217
249
|
|
|
218
250
|
items = expr_val.get_value(subject)
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
]
|
|
222
|
-
unified_numeric_type = register_info_to_quantum_type(
|
|
223
|
-
aggregate_numeric_types(numeric_types)
|
|
224
|
-
)
|
|
225
|
-
expr_val.set_type(node, unified_numeric_type)
|
|
251
|
+
result_attrs = compute_result_attrs_quantum_subscript(items, machine_precision)
|
|
252
|
+
expr_val.set_type(node, result_attrs.to_quantum_numeric())
|