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
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
from typing import
|
|
1
|
+
from typing import TYPE_CHECKING, Any, NoReturn, TypeVar, Union
|
|
2
2
|
|
|
3
3
|
import sympy
|
|
4
4
|
|
|
@@ -6,14 +6,17 @@ from classiq.interface.exceptions import (
|
|
|
6
6
|
ClassiqExpansionError,
|
|
7
7
|
ClassiqInternalExpansionError,
|
|
8
8
|
)
|
|
9
|
-
from classiq.interface.generator.expressions.
|
|
10
|
-
|
|
11
|
-
AnyClassicalValue,
|
|
9
|
+
from classiq.interface.generator.expressions.evaluated_expression import (
|
|
10
|
+
EvaluatedExpression,
|
|
12
11
|
)
|
|
12
|
+
from classiq.interface.generator.expressions.expression import Expression
|
|
13
|
+
from classiq.interface.generator.expressions.expression_types import RuntimeConstant
|
|
13
14
|
from classiq.interface.generator.functions.classical_type import (
|
|
15
|
+
Bool,
|
|
14
16
|
ClassicalArray,
|
|
15
17
|
ClassicalTuple,
|
|
16
18
|
ClassicalType,
|
|
19
|
+
Integer,
|
|
17
20
|
)
|
|
18
21
|
from classiq.interface.generator.functions.concrete_types import ConcreteQuantumType
|
|
19
22
|
from classiq.interface.generator.functions.port_declaration import (
|
|
@@ -22,12 +25,14 @@ from classiq.interface.generator.functions.port_declaration import (
|
|
|
22
25
|
from classiq.interface.generator.functions.type_name import (
|
|
23
26
|
TypeName,
|
|
24
27
|
)
|
|
28
|
+
from classiq.interface.helpers.backward_compatibility import zip_strict
|
|
25
29
|
from classiq.interface.model.classical_parameter_declaration import (
|
|
26
30
|
ClassicalParameterDeclaration,
|
|
27
31
|
)
|
|
28
32
|
from classiq.interface.model.handle_binding import HandleBinding
|
|
29
33
|
from classiq.interface.model.port_declaration import PortDeclaration
|
|
30
34
|
from classiq.interface.model.quantum_function_declaration import (
|
|
35
|
+
AnonQuantumOperandDeclaration,
|
|
31
36
|
PositionalArg,
|
|
32
37
|
QuantumOperandDeclaration,
|
|
33
38
|
)
|
|
@@ -38,71 +43,62 @@ from classiq.interface.model.quantum_type import (
|
|
|
38
43
|
QuantumType,
|
|
39
44
|
)
|
|
40
45
|
|
|
41
|
-
from classiq.evaluators.arg_type_match import check_type_match
|
|
42
46
|
from classiq.evaluators.classical_expression import (
|
|
43
47
|
evaluate_classical_expression,
|
|
44
48
|
)
|
|
45
|
-
from classiq.evaluators.
|
|
49
|
+
from classiq.evaluators.qmod_annotated_expression import QmodAnnotatedExpression
|
|
50
|
+
from classiq.evaluators.qmod_node_evaluators.utils import QmodType, get_sympy_val
|
|
51
|
+
from classiq.evaluators.qmod_type_inference.classical_type_inference import (
|
|
46
52
|
infer_classical_type,
|
|
53
|
+
inject_classical_type_attributes,
|
|
47
54
|
)
|
|
48
55
|
from classiq.evaluators.qmod_type_inference.quantum_type_inference import (
|
|
49
56
|
inject_quantum_type_attributes,
|
|
57
|
+
validate_quantum_type_attributes,
|
|
50
58
|
)
|
|
59
|
+
from classiq.evaluators.type_type_match import check_signature_match
|
|
51
60
|
from classiq.model_expansions.closure import FunctionClosure
|
|
52
61
|
from classiq.model_expansions.scope import (
|
|
62
|
+
ClassicalSymbol,
|
|
53
63
|
Evaluated,
|
|
54
64
|
QuantumSymbol,
|
|
55
65
|
QuantumVariable,
|
|
56
66
|
Scope,
|
|
57
67
|
)
|
|
68
|
+
from classiq.model_expansions.visitors.symbolic_param_inference import (
|
|
69
|
+
set_generative_recursively,
|
|
70
|
+
)
|
|
58
71
|
|
|
59
72
|
|
|
60
73
|
def evaluate_parameter_types_from_args(
|
|
61
|
-
closure: FunctionClosure,
|
|
74
|
+
closure: FunctionClosure, arguments: list[Evaluated]
|
|
62
75
|
) -> list[PositionalArg]:
|
|
63
76
|
parameters = closure.positional_arg_declarations
|
|
64
|
-
|
|
65
|
-
|
|
77
|
+
if len(parameters) != len(arguments):
|
|
78
|
+
raise ClassiqExpansionError(
|
|
79
|
+
f"Function {closure.name!r} takes {len(parameters)} arguments but "
|
|
80
|
+
f"{len(arguments)} were given"
|
|
81
|
+
)
|
|
82
|
+
|
|
83
|
+
for parameter, argument in zip_strict(parameters, arguments, strict=True):
|
|
84
|
+
if isinstance(parameter, ClassicalParameterDeclaration):
|
|
85
|
+
arg_val = argument.value
|
|
86
|
+
if not isinstance(arg_val, QmodAnnotatedExpression):
|
|
87
|
+
closure.scope[parameter.name] = argument
|
|
66
88
|
|
|
67
|
-
|
|
68
|
-
|
|
89
|
+
evaluated_params = [
|
|
90
|
+
_evaluate_type_from_arg(parameter, argument, closure)
|
|
91
|
+
for parameter, argument in zip_strict(parameters, arguments, strict=True)
|
|
92
|
+
]
|
|
69
93
|
|
|
70
94
|
parameter_names = {parameter.name for parameter in parameters}
|
|
71
|
-
for parameter in parameters:
|
|
95
|
+
for parameter, argument in zip_strict(parameters, arguments, strict=True):
|
|
72
96
|
if isinstance(parameter, QuantumOperandDeclaration):
|
|
73
|
-
parameter_value = closure.scope[parameter.name].value
|
|
74
97
|
_update_operand_signature_environment(
|
|
75
|
-
|
|
98
|
+
argument.value, parameter_names, closure
|
|
76
99
|
)
|
|
77
100
|
|
|
78
|
-
return
|
|
79
|
-
_evaluate_type_from_arg(
|
|
80
|
-
parameter,
|
|
81
|
-
argument,
|
|
82
|
-
Scope(parent=closure.scope | signature_scope),
|
|
83
|
-
closure.name,
|
|
84
|
-
)
|
|
85
|
-
for parameter, argument in zip(parameters, arguments)
|
|
86
|
-
]
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
def _update_scope(
|
|
90
|
-
parameter: PositionalArg, argument: Evaluated, closure: FunctionClosure
|
|
91
|
-
) -> None:
|
|
92
|
-
if not isinstance(parameter, PortDeclaration):
|
|
93
|
-
closure.scope[parameter.name] = argument
|
|
94
|
-
return
|
|
95
|
-
if parameter.direction is PortDeclarationDirection.Output:
|
|
96
|
-
return
|
|
97
|
-
quantum_var = argument.as_type(QuantumVariable)
|
|
98
|
-
casted_argument = _cast(
|
|
99
|
-
parameter.quantum_type,
|
|
100
|
-
quantum_var,
|
|
101
|
-
parameter.name,
|
|
102
|
-
)
|
|
103
|
-
closure.scope[parameter.name] = Evaluated(
|
|
104
|
-
value=casted_argument, defining_function=closure
|
|
105
|
-
)
|
|
101
|
+
return evaluated_params
|
|
106
102
|
|
|
107
103
|
|
|
108
104
|
NestedFunctionClosureT = Union[FunctionClosure, list["NestedFunctionClosureT"]]
|
|
@@ -130,60 +126,162 @@ def _update_operand_signature_environment(
|
|
|
130
126
|
)
|
|
131
127
|
|
|
132
128
|
|
|
133
|
-
def _cast(
|
|
134
|
-
parameter_type: QuantumType, argument: QuantumVariable, param_name: str
|
|
135
|
-
) -> QuantumSymbol:
|
|
136
|
-
updated_type = inject_quantum_type_attributes(argument.quantum_type, parameter_type)
|
|
137
|
-
if updated_type is None:
|
|
138
|
-
raise ClassiqExpansionError(
|
|
139
|
-
f"Argument {str(argument)!r} of type "
|
|
140
|
-
f"{argument.quantum_type.qmod_type_name} is incompatible with parameter "
|
|
141
|
-
f"{param_name!r} of type {parameter_type.qmod_type_name}"
|
|
142
|
-
)
|
|
143
|
-
return QuantumSymbol(
|
|
144
|
-
handle=HandleBinding(name=param_name), quantum_type=updated_type
|
|
145
|
-
)
|
|
146
|
-
|
|
147
|
-
|
|
148
129
|
def _evaluate_type_from_arg(
|
|
149
130
|
parameter: PositionalArg,
|
|
150
131
|
argument: Evaluated,
|
|
151
|
-
|
|
152
|
-
function_name: str,
|
|
132
|
+
closure: FunctionClosure,
|
|
153
133
|
) -> PositionalArg:
|
|
154
134
|
# FIXME: Remove suzuki_trotter overloading (CLS-2912)
|
|
155
|
-
if
|
|
135
|
+
if closure.name == "suzuki_trotter" and parameter.name == "pauli_operator":
|
|
156
136
|
return parameter
|
|
157
137
|
if isinstance(parameter, ClassicalParameterDeclaration):
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
)
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
138
|
+
return _evaluate_classical_type_from_arg(parameter, argument, closure)
|
|
139
|
+
if isinstance(parameter, PortDeclaration):
|
|
140
|
+
return _evaluate_quantum_type_from_arg(parameter, argument, closure)
|
|
141
|
+
if TYPE_CHECKING:
|
|
142
|
+
assert isinstance(parameter, QuantumOperandDeclaration)
|
|
143
|
+
if parameter.is_list:
|
|
144
|
+
return _evaluate_op_list_type_from_arg(parameter, argument, closure)
|
|
145
|
+
else:
|
|
146
|
+
return _evaluate_op_type_from_arg(parameter, argument, closure)
|
|
147
|
+
|
|
148
|
+
|
|
149
|
+
def _evaluate_classical_type_from_arg(
|
|
150
|
+
parameter: ClassicalParameterDeclaration,
|
|
151
|
+
argument: Evaluated,
|
|
152
|
+
closure: FunctionClosure,
|
|
153
|
+
) -> ClassicalParameterDeclaration:
|
|
154
|
+
unified_scope = closure.scope | closure.signature_scope
|
|
155
|
+
updated_classical_type = evaluate_type_in_classical_symbol(
|
|
156
|
+
parameter.classical_type.model_copy(), unified_scope, parameter.name
|
|
157
|
+
)
|
|
158
|
+
arg_val = argument.value
|
|
159
|
+
if isinstance(arg_val, QmodAnnotatedExpression):
|
|
160
|
+
arg_type = arg_val.get_classical_type(arg_val.root)
|
|
161
|
+
else:
|
|
162
|
+
arg_type = infer_classical_type(arg_val)
|
|
163
|
+
injected_classical_type = inject_classical_type_attributes(
|
|
164
|
+
arg_type.without_symbolic_attributes(), updated_classical_type
|
|
165
|
+
)
|
|
166
|
+
if injected_classical_type is None:
|
|
167
|
+
_raise_argument_type_error(
|
|
168
|
+
arg_val, arg_type, parameter.name, updated_classical_type
|
|
164
169
|
)
|
|
170
|
+
if parameter.classical_type.is_purely_generative:
|
|
171
|
+
set_generative_recursively(injected_classical_type)
|
|
172
|
+
closure.scope[parameter.name] = Evaluated(
|
|
173
|
+
value=(
|
|
174
|
+
ClassicalSymbol(
|
|
175
|
+
handle=HandleBinding(name=parameter.name),
|
|
176
|
+
classical_type=injected_classical_type,
|
|
177
|
+
)
|
|
178
|
+
if isinstance(arg_val, QmodAnnotatedExpression)
|
|
179
|
+
else arg_val
|
|
180
|
+
),
|
|
181
|
+
defining_function=closure,
|
|
182
|
+
)
|
|
183
|
+
return ClassicalParameterDeclaration(
|
|
184
|
+
name=parameter.name, classical_type=injected_classical_type
|
|
185
|
+
)
|
|
165
186
|
|
|
166
|
-
if not isinstance(parameter, PortDeclaration):
|
|
167
|
-
return parameter
|
|
168
187
|
|
|
188
|
+
def _evaluate_quantum_type_from_arg(
|
|
189
|
+
parameter: PortDeclaration,
|
|
190
|
+
argument: Evaluated,
|
|
191
|
+
closure: FunctionClosure,
|
|
192
|
+
) -> PortDeclaration:
|
|
193
|
+
unified_scope = closure.scope | closure.signature_scope
|
|
169
194
|
updated_quantum_type: QuantumType = evaluate_type_in_quantum_symbol(
|
|
170
|
-
parameter.quantum_type.model_copy(),
|
|
195
|
+
parameter.quantum_type.model_copy(), unified_scope, parameter.name
|
|
171
196
|
)
|
|
172
197
|
if parameter.direction != PortDeclarationDirection.Output:
|
|
173
198
|
arg_type = argument.as_type(QuantumVariable).quantum_type
|
|
174
199
|
updated_output_quantum_type = inject_quantum_type_attributes(
|
|
175
|
-
arg_type, updated_quantum_type
|
|
200
|
+
arg_type.without_symbolic_attributes(), updated_quantum_type
|
|
176
201
|
)
|
|
177
202
|
if updated_output_quantum_type is None:
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
f"{arg_type.qmod_type_name} is incompatible with parameter "
|
|
181
|
-
f"{parameter.name!r} of type {updated_quantum_type.qmod_type_name}"
|
|
203
|
+
_raise_argument_type_error(
|
|
204
|
+
argument.value, arg_type, parameter.name, updated_quantum_type
|
|
182
205
|
)
|
|
183
206
|
updated_quantum_type = updated_output_quantum_type
|
|
207
|
+
validate_quantum_type_attributes(updated_quantum_type)
|
|
208
|
+
closure.scope[parameter.name] = Evaluated(
|
|
209
|
+
value=QuantumSymbol(
|
|
210
|
+
handle=HandleBinding(name=parameter.name), quantum_type=updated_quantum_type
|
|
211
|
+
),
|
|
212
|
+
defining_function=closure,
|
|
213
|
+
)
|
|
184
214
|
return parameter.model_copy(update={"quantum_type": updated_quantum_type})
|
|
185
215
|
|
|
186
216
|
|
|
217
|
+
def _evaluate_op_list_type_from_arg(
|
|
218
|
+
parameter: QuantumOperandDeclaration, argument: Evaluated, closure: FunctionClosure
|
|
219
|
+
) -> QuantumOperandDeclaration:
|
|
220
|
+
arg_val = argument.value
|
|
221
|
+
if not isinstance(arg_val, list) or any(
|
|
222
|
+
not isinstance(op, FunctionClosure) for op in arg_val
|
|
223
|
+
):
|
|
224
|
+
if isinstance(arg_val, FunctionClosure):
|
|
225
|
+
_raise_argument_type_error(
|
|
226
|
+
"<lambda>",
|
|
227
|
+
arg_val.as_operand_declaration(is_list=False),
|
|
228
|
+
parameter.name,
|
|
229
|
+
parameter,
|
|
230
|
+
)
|
|
231
|
+
raise ClassiqInternalExpansionError("Non-lambda argument to lambda parameter")
|
|
232
|
+
for idx, operand in enumerate(arg_val):
|
|
233
|
+
check_signature_match(
|
|
234
|
+
parameter.positional_arg_declarations,
|
|
235
|
+
operand.positional_arg_declarations,
|
|
236
|
+
f"operand #{idx + 1} in parameter {parameter.name!r} "
|
|
237
|
+
f"in function {closure.name!r}",
|
|
238
|
+
)
|
|
239
|
+
return parameter
|
|
240
|
+
|
|
241
|
+
|
|
242
|
+
def _evaluate_op_type_from_arg(
|
|
243
|
+
parameter: QuantumOperandDeclaration, argument: Evaluated, closure: FunctionClosure
|
|
244
|
+
) -> QuantumOperandDeclaration:
|
|
245
|
+
arg_val = argument.value
|
|
246
|
+
if not isinstance(arg_val, FunctionClosure):
|
|
247
|
+
if isinstance(arg_val, list):
|
|
248
|
+
if len(arg_val) == 0:
|
|
249
|
+
_raise_argument_type_error(
|
|
250
|
+
arg_val,
|
|
251
|
+
AnonQuantumOperandDeclaration(is_list=True),
|
|
252
|
+
parameter.name,
|
|
253
|
+
parameter,
|
|
254
|
+
)
|
|
255
|
+
first_lambda = arg_val[0]
|
|
256
|
+
if isinstance(first_lambda, FunctionClosure):
|
|
257
|
+
_raise_argument_type_error(
|
|
258
|
+
arg_val,
|
|
259
|
+
first_lambda.as_operand_declaration(is_list=True),
|
|
260
|
+
parameter.name,
|
|
261
|
+
parameter,
|
|
262
|
+
)
|
|
263
|
+
raise ClassiqInternalExpansionError("Non-lambda argument to lambda parameter")
|
|
264
|
+
check_signature_match(
|
|
265
|
+
parameter.positional_arg_declarations,
|
|
266
|
+
arg_val.positional_arg_declarations,
|
|
267
|
+
f"operand {parameter.name!r} in function {closure.name!r}",
|
|
268
|
+
)
|
|
269
|
+
return parameter
|
|
270
|
+
|
|
271
|
+
|
|
272
|
+
def _raise_argument_type_error(
|
|
273
|
+
arg_val: Any,
|
|
274
|
+
arg_type: Union[QmodType, AnonQuantumOperandDeclaration],
|
|
275
|
+
param_name: str,
|
|
276
|
+
param_type: Union[QmodType, AnonQuantumOperandDeclaration],
|
|
277
|
+
) -> NoReturn:
|
|
278
|
+
raise ClassiqExpansionError(
|
|
279
|
+
f"Argument {str(arg_val)!r} of type "
|
|
280
|
+
f"{arg_type.qmod_type_name} is incompatible with parameter "
|
|
281
|
+
f"{param_name!r} of type {param_type.qmod_type_name}"
|
|
282
|
+
)
|
|
283
|
+
|
|
284
|
+
|
|
187
285
|
def evaluate_type_in_quantum_symbol(
|
|
188
286
|
type_to_update: QuantumType, scope: Scope, param_name: str
|
|
189
287
|
) -> ConcreteQuantumType:
|
|
@@ -206,16 +304,15 @@ def _evaluate_qarray_in_quantum_symbol(
|
|
|
206
304
|
)
|
|
207
305
|
type_to_update.element_type = new_element_type
|
|
208
306
|
if type_to_update.length is not None:
|
|
209
|
-
|
|
307
|
+
type_to_update.length = _eval_expr(
|
|
210
308
|
type_to_update.length,
|
|
211
309
|
scope,
|
|
212
310
|
int,
|
|
311
|
+
Integer,
|
|
213
312
|
type_to_update.type_name,
|
|
214
313
|
"length",
|
|
215
314
|
param_name,
|
|
216
315
|
)
|
|
217
|
-
if new_length is not None:
|
|
218
|
-
type_to_update.length = Expression(expr=str(new_length))
|
|
219
316
|
return type_to_update
|
|
220
317
|
|
|
221
318
|
|
|
@@ -224,73 +321,74 @@ def _evaluate_qnum_in_quantum_symbol(
|
|
|
224
321
|
) -> QuantumNumeric:
|
|
225
322
|
if type_to_update.size is None:
|
|
226
323
|
return type_to_update
|
|
227
|
-
|
|
324
|
+
type_to_update.size = _eval_expr(
|
|
228
325
|
type_to_update.size,
|
|
229
326
|
scope,
|
|
230
327
|
int,
|
|
328
|
+
Integer,
|
|
231
329
|
type_to_update.type_name,
|
|
232
330
|
"size",
|
|
233
331
|
param_name,
|
|
234
332
|
)
|
|
235
|
-
if new_size is not None:
|
|
236
|
-
type_to_update.size = Expression(expr=str(new_size))
|
|
237
333
|
|
|
238
334
|
if type_to_update.is_signed is not None:
|
|
239
|
-
|
|
335
|
+
type_to_update.is_signed = _eval_expr(
|
|
240
336
|
type_to_update.is_signed,
|
|
241
337
|
scope,
|
|
242
338
|
bool,
|
|
339
|
+
Bool,
|
|
243
340
|
type_to_update.type_name,
|
|
244
341
|
"sign",
|
|
245
342
|
param_name,
|
|
246
343
|
)
|
|
247
|
-
if new_is_sign is not None:
|
|
248
|
-
type_to_update.is_signed = Expression(expr=str(new_is_sign))
|
|
249
344
|
else:
|
|
250
345
|
type_to_update.is_signed = Expression(expr="False")
|
|
251
346
|
|
|
252
347
|
if type_to_update.fraction_digits is not None:
|
|
253
|
-
|
|
348
|
+
type_to_update.fraction_digits = _eval_expr(
|
|
254
349
|
type_to_update.fraction_digits,
|
|
255
350
|
scope,
|
|
256
351
|
int,
|
|
352
|
+
Integer,
|
|
257
353
|
type_to_update.type_name,
|
|
258
354
|
"fraction digits",
|
|
259
355
|
param_name,
|
|
260
356
|
)
|
|
261
|
-
if new_fraction_digits is not None:
|
|
262
|
-
type_to_update.fraction_digits = Expression(expr=str(new_fraction_digits))
|
|
263
357
|
else:
|
|
264
358
|
type_to_update.fraction_digits = Expression(expr="0")
|
|
265
359
|
|
|
266
360
|
return type_to_update
|
|
267
361
|
|
|
268
362
|
|
|
269
|
-
_EXPR_TYPE = TypeVar("_EXPR_TYPE")
|
|
363
|
+
_EXPR_TYPE = TypeVar("_EXPR_TYPE", bound=RuntimeConstant)
|
|
270
364
|
|
|
271
365
|
|
|
272
366
|
def _eval_expr(
|
|
273
367
|
expression: Expression,
|
|
274
368
|
scope: Scope,
|
|
275
369
|
expected_type: type[_EXPR_TYPE],
|
|
370
|
+
expected_qmod_type: type,
|
|
276
371
|
type_name: str,
|
|
277
372
|
attr_name: str,
|
|
278
373
|
param_name: str,
|
|
279
|
-
) ->
|
|
280
|
-
val = evaluate_classical_expression(expression, scope).value
|
|
281
|
-
if
|
|
374
|
+
) -> Expression:
|
|
375
|
+
val = evaluate_classical_expression(Expression(expr=expression.expr), scope).value
|
|
376
|
+
if isinstance(val, sympy.Basic):
|
|
377
|
+
val = get_sympy_val(val)
|
|
378
|
+
if expected_type is int and isinstance(val, float) and int(val) == val:
|
|
282
379
|
val = int(val)
|
|
283
|
-
if isinstance(val, expected_type)
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
isinstance(val, sympy.Basic) and len(val.free_symbols) > 0
|
|
380
|
+
if not isinstance(val, expected_type) and (
|
|
381
|
+
not isinstance(val, QmodAnnotatedExpression)
|
|
382
|
+
or not isinstance(val.get_type(val.root), expected_qmod_type)
|
|
287
383
|
):
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
)
|
|
384
|
+
raise ClassiqExpansionError(
|
|
385
|
+
f"When inferring the type of parameter {param_name!r}: "
|
|
386
|
+
f"{type_name} {attr_name} must be {expected_qmod_type.__name__}, got "
|
|
387
|
+
f"{str(val)!r}"
|
|
388
|
+
)
|
|
389
|
+
expr = Expression(expr=str(val))
|
|
390
|
+
expr._evaluated_expr = EvaluatedExpression(value=val)
|
|
391
|
+
return expr
|
|
294
392
|
|
|
295
393
|
|
|
296
394
|
def _evaluate_qstruct_in_quantum_symbol(
|
|
@@ -325,11 +423,9 @@ def evaluate_type_in_classical_symbol(
|
|
|
325
423
|
if isinstance(type_to_update, ClassicalArray):
|
|
326
424
|
length = type_to_update.length
|
|
327
425
|
if length is not None:
|
|
328
|
-
|
|
329
|
-
length, scope, int, "classical array", "length", param_name
|
|
426
|
+
length = _eval_expr(
|
|
427
|
+
length, scope, int, Integer, "classical array", "length", param_name
|
|
330
428
|
)
|
|
331
|
-
if new_length is not None:
|
|
332
|
-
length = Expression(expr=str(new_length))
|
|
333
429
|
updated_type = ClassicalArray(
|
|
334
430
|
element_type=evaluate_type_in_classical_symbol(
|
|
335
431
|
type_to_update.element_type, scope, param_name
|
|
@@ -4,6 +4,8 @@ from dataclasses import dataclass
|
|
|
4
4
|
from enum import Enum
|
|
5
5
|
from typing import Any, Union, cast
|
|
6
6
|
|
|
7
|
+
import sympy
|
|
8
|
+
|
|
7
9
|
from classiq.interface.exceptions import ClassiqInternalExpansionError
|
|
8
10
|
from classiq.interface.generator.expressions.proxies.classical.qmod_struct_instance import (
|
|
9
11
|
QmodStructInstance,
|
|
@@ -50,7 +52,7 @@ def qmod_val_to_str(val: Any) -> str:
|
|
|
50
52
|
return f"[{', '.join(qmod_val_to_str(item) for item in val)}]"
|
|
51
53
|
if isinstance(val, Enum):
|
|
52
54
|
return Enum.__str__(val)
|
|
53
|
-
if isinstance(val, (int, float, bool, complex)):
|
|
55
|
+
if isinstance(val, (int, float, bool, complex, sympy.Basic)):
|
|
54
56
|
return str(val)
|
|
55
57
|
raise ClassiqInternalExpansionError(
|
|
56
58
|
f"Unrecognized value {str(val)!r} of type {type(val)}"
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import ast
|
|
2
|
-
from typing import
|
|
2
|
+
from typing import Callable, Union, cast
|
|
3
3
|
|
|
4
4
|
import sympy
|
|
5
5
|
|
|
@@ -184,37 +184,25 @@ def try_eval_sympy_function(
|
|
|
184
184
|
if not isinstance(sympy_func, sympy.FunctionClass):
|
|
185
185
|
return False
|
|
186
186
|
_validate_no_kwargs(node)
|
|
187
|
-
args: Optional[list[Any]] = None
|
|
188
|
-
sympy_ret_val: Any = None
|
|
189
|
-
if all(expr_val.has_value(arg) for arg in node.args):
|
|
190
|
-
args = [expr_val.get_value(arg) for arg in node.args]
|
|
191
|
-
sympy_ret_val = sympy_func(*args)
|
|
192
|
-
if not isinstance(sympy_ret_val, sympy.Expr):
|
|
193
|
-
raise ClassiqInternalExpansionError
|
|
194
187
|
ret_type: QmodType
|
|
195
|
-
ret_val: Any = None
|
|
196
188
|
if hasattr(sympy_func, "is_Boolean") and sympy_func.is_Boolean:
|
|
197
189
|
ret_type = Bool()
|
|
198
|
-
if args is not None:
|
|
199
|
-
ret_val = bool(sympy_ret_val)
|
|
200
190
|
elif (
|
|
201
191
|
hasattr(sympy_func, "is_Integer") and sympy_func.is_Integer
|
|
202
192
|
) or func_name in INTEGER_FUNCTION_OVERRIDE:
|
|
203
193
|
ret_type = Integer()
|
|
204
|
-
if args is not None:
|
|
205
|
-
ret_val = int(sympy_ret_val)
|
|
206
194
|
else:
|
|
207
195
|
ret_type = Real()
|
|
208
|
-
if sympy_ret_val is not None:
|
|
209
|
-
if sympy_ret_val.is_imaginary:
|
|
210
|
-
ret_val = complex(sympy_ret_val)
|
|
211
|
-
elif sympy_ret_val.is_real:
|
|
212
|
-
ret_val = float(sympy_ret_val)
|
|
213
|
-
else:
|
|
214
|
-
raise ClassiqInternalExpansionError
|
|
215
196
|
expr_val.set_type(node, ret_type)
|
|
216
|
-
|
|
217
|
-
|
|
197
|
+
|
|
198
|
+
if any(not expr_val.has_value(arg) for arg in node.args):
|
|
199
|
+
return True
|
|
200
|
+
|
|
201
|
+
args = [expr_val.get_value(arg) for arg in node.args]
|
|
202
|
+
sympy_ret_val = sympy_func(*args)
|
|
203
|
+
if not isinstance(sympy_ret_val, sympy.Basic):
|
|
204
|
+
raise ClassiqInternalExpansionError
|
|
205
|
+
expr_val.set_value(node, sympy_ret_val)
|
|
218
206
|
return True
|
|
219
207
|
|
|
220
208
|
|
|
@@ -265,14 +253,7 @@ def try_eval_builtin_function(
|
|
|
265
253
|
sympy_val = sympy.mod_inverse(
|
|
266
254
|
*[expr_val.get_value(arg) for arg in node.args]
|
|
267
255
|
)
|
|
268
|
-
|
|
269
|
-
if isinstance(sympy_val, sympy.Expr) and sympy_val.is_imaginary:
|
|
270
|
-
ret_val = complex(sympy_val)
|
|
271
|
-
elif args_are_int:
|
|
272
|
-
ret_val = int(sympy_val)
|
|
273
|
-
else:
|
|
274
|
-
ret_val = float(sympy_val)
|
|
275
|
-
expr_val.set_value(node, ret_val)
|
|
256
|
+
expr_val.set_value(node, sympy_val)
|
|
276
257
|
return True
|
|
277
258
|
|
|
278
259
|
if func_name == "sum":
|
|
@@ -293,13 +274,7 @@ def try_eval_builtin_function(
|
|
|
293
274
|
expr_val.set_type(node, Real())
|
|
294
275
|
if args_have_values:
|
|
295
276
|
sympy_val = sympy.sqrt(*[expr_val.get_value(arg) for arg in node.args])
|
|
296
|
-
|
|
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)
|
|
277
|
+
expr_val.set_value(node, sympy_val)
|
|
303
278
|
return True
|
|
304
279
|
|
|
305
280
|
if func_name == "abs":
|
|
@@ -16,7 +16,11 @@ from classiq.interface.generator.functions.classical_type import (
|
|
|
16
16
|
from classiq.interface.generator.functions.type_name import Enum
|
|
17
17
|
|
|
18
18
|
from classiq.evaluators.qmod_annotated_expression import QmodAnnotatedExpression
|
|
19
|
-
from classiq.evaluators.qmod_node_evaluators.utils import
|
|
19
|
+
from classiq.evaluators.qmod_node_evaluators.utils import (
|
|
20
|
+
SYMPY_SYMBOLS,
|
|
21
|
+
QmodType,
|
|
22
|
+
get_sympy_type,
|
|
23
|
+
)
|
|
20
24
|
|
|
21
25
|
QMOD_LITERALS: dict[str, tuple[ClassicalType, Any]] = {
|
|
22
26
|
"false": (Bool(), False),
|
|
@@ -68,22 +72,9 @@ def try_eval_qmod_literal(expr_val: QmodAnnotatedExpression, node: ast.Name) ->
|
|
|
68
72
|
|
|
69
73
|
def try_eval_sympy_constant(expr_val: QmodAnnotatedExpression, node: ast.Name) -> bool:
|
|
70
74
|
sympy_val = SYMPY_SYMBOLS.get(node.id)
|
|
71
|
-
if not isinstance(sympy_val, sympy.
|
|
75
|
+
if not isinstance(sympy_val, sympy.Basic) or len(sympy_val.free_symbols) > 0:
|
|
72
76
|
return False
|
|
73
|
-
constant_type
|
|
74
|
-
constant_value: Any
|
|
75
|
-
if sympy_val.is_Integer:
|
|
76
|
-
constant_type = Integer()
|
|
77
|
-
constant_value = int(sympy_val)
|
|
78
|
-
elif sympy_val.is_Boolean:
|
|
79
|
-
constant_type = Bool()
|
|
80
|
-
constant_value = bool(sympy_val)
|
|
81
|
-
elif sympy_val.is_imaginary:
|
|
82
|
-
constant_type = Real()
|
|
83
|
-
constant_value = complex(sympy_val)
|
|
84
|
-
else:
|
|
85
|
-
constant_type = Real()
|
|
86
|
-
constant_value = float(sympy_val)
|
|
77
|
+
constant_type = get_sympy_type(sympy_val)
|
|
87
78
|
expr_val.set_type(node, constant_type)
|
|
88
|
-
expr_val.set_value(node,
|
|
79
|
+
expr_val.set_value(node, sympy_val)
|
|
89
80
|
return True
|
|
@@ -21,5 +21,5 @@ def eval_measurement(expr_val: QmodAnnotatedExpression, node: ast.Call) -> None:
|
|
|
21
21
|
if is_classical_type(arg_type):
|
|
22
22
|
raise ClassiqExpansionError("'measure' expects a quantum input")
|
|
23
23
|
if not isinstance(arg_type, QuantumBit):
|
|
24
|
-
raise ClassiqExpansionError("
|
|
24
|
+
raise ClassiqExpansionError("'measure' only supports QBits")
|
|
25
25
|
expr_val.set_type(node, Bool())
|
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
import ast
|
|
2
2
|
|
|
3
|
+
import sympy
|
|
4
|
+
|
|
3
5
|
from classiq.interface.exceptions import (
|
|
4
6
|
ClassiqExpansionError,
|
|
5
7
|
ClassiqInternalExpansionError,
|
|
@@ -84,7 +86,11 @@ def eval_min_max_op(
|
|
|
84
86
|
|
|
85
87
|
if all(expr_val.has_value(arg) for arg in node.args):
|
|
86
88
|
values = [expr_val.get_value(arg) for arg in node.args]
|
|
87
|
-
if not all(
|
|
89
|
+
if not all(
|
|
90
|
+
isinstance(value, (int, float))
|
|
91
|
+
or (isinstance(value, sympy.Expr) and value.is_real)
|
|
92
|
+
for value in values
|
|
93
|
+
):
|
|
88
94
|
raise ClassiqExpansionError(f"Invalid argument for function {func_name!r}")
|
|
89
95
|
|
|
90
96
|
if func_name == "min":
|
|
@@ -22,7 +22,6 @@ from classiq.evaluators.qmod_type_inference.classical_type_inference import (
|
|
|
22
22
|
|
|
23
23
|
|
|
24
24
|
def eval_name(expr_val: QmodAnnotatedExpression, node: ast.Name, value: Any) -> None:
|
|
25
|
-
# FIXME: Remove sympy compatibility (CLS-3214)
|
|
26
25
|
if isinstance(
|
|
27
26
|
value, (bool, int, float, complex, list, QmodStructInstance, sympy.Basic)
|
|
28
27
|
):
|
|
@@ -1,12 +1,18 @@
|
|
|
1
1
|
import ast
|
|
2
2
|
from typing import TYPE_CHECKING, Optional
|
|
3
3
|
|
|
4
|
+
import sympy
|
|
5
|
+
|
|
4
6
|
from classiq.interface.exceptions import ClassiqExpansionError
|
|
5
7
|
from classiq.interface.generator.functions.classical_type import Bool
|
|
6
8
|
from classiq.interface.model.quantum_type import QuantumScalar
|
|
7
9
|
|
|
8
10
|
from classiq.evaluators.qmod_annotated_expression import QmodAnnotatedExpression
|
|
9
|
-
from classiq.evaluators.qmod_node_evaluators.utils import
|
|
11
|
+
from classiq.evaluators.qmod_node_evaluators.utils import (
|
|
12
|
+
QmodType,
|
|
13
|
+
get_sympy_val,
|
|
14
|
+
is_classical_type,
|
|
15
|
+
)
|
|
10
16
|
from classiq.model_expansions.arithmetic import NumericAttributes
|
|
11
17
|
|
|
12
18
|
|
|
@@ -46,6 +52,8 @@ def get_classical_value_for_arithmetic(
|
|
|
46
52
|
return None
|
|
47
53
|
|
|
48
54
|
value = expr_val.get_value(node)
|
|
55
|
+
if isinstance(value, sympy.Basic):
|
|
56
|
+
value = get_sympy_val(value)
|
|
49
57
|
if not isinstance(value, (int, float)):
|
|
50
58
|
if treat_qnum_as_float and isinstance(value, complex):
|
|
51
59
|
return None
|