classiq 0.88.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/_internals/config.py +1 -1
- 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 +10 -9
- classiq/evaluators/qmod_expression_visitors/qmod_expression_evaluator.py +2 -2
- classiq/evaluators/qmod_expression_visitors/qmod_expression_renamer.py +1 -1
- classiq/evaluators/qmod_node_evaluators/attribute_evaluation.py +66 -5
- 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 +2 -26
- classiq/interface/analyzer/result.py +4 -0
- classiq/interface/backend/backend_preferences.py +1 -1
- 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/arith/register_user_input.py +1 -1
- 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/classical_type.py +24 -3
- classiq/interface/generator/functions/concrete_types.py +1 -1
- classiq/interface/generator/functions/function_declaration.py +0 -4
- classiq/interface/generator/functions/type_name.py +25 -0
- classiq/interface/generator/generated_circuit_data.py +4 -0
- classiq/interface/generator/hardware_efficient_ansatz.py +1 -1
- classiq/interface/generator/preferences/qasm_to_qmod_params.py +14 -0
- classiq/interface/generator/quantum_function_call.py +3 -3
- classiq/interface/generator/user_defined_function_params.py +0 -3
- classiq/interface/helpers/model_normalizer.py +0 -6
- classiq/interface/ide/ide_data.py +1 -1
- classiq/interface/ide/visual_model.py +3 -2
- classiq/interface/model/block.py +5 -1
- classiq/interface/model/handle_binding.py +2 -2
- classiq/interface/model/port_declaration.py +2 -1
- classiq/interface/model/quantum_expressions/arithmetic_operation.py +16 -12
- classiq/interface/model/quantum_lambda_function.py +1 -1
- classiq/interface/model/quantum_statement.py +2 -4
- classiq/interface/model/quantum_type.py +47 -4
- 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/__init__.py +2 -0
- classiq/open_library/functions/state_preparation.py +140 -5
- 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 +62 -16
- classiq/qmod/quantum_expandable.py +1 -1
- classiq/synthesis.py +37 -1
- classiq/visualization.py +1 -1
- {classiq-0.88.0.dist-info → classiq-0.90.0.dist-info}/METADATA +2 -2
- {classiq-0.88.0.dist-info → classiq-0.90.0.dist-info}/RECORD +98 -102
- 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.88.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,
|
|
@@ -30,7 +32,7 @@ class QuantumSubscriptAnnotation:
|
|
|
30
32
|
|
|
31
33
|
@dataclass(frozen=True)
|
|
32
34
|
class QuantumTypeAttributeAnnotation:
|
|
33
|
-
value:
|
|
35
|
+
value: HandleBinding
|
|
34
36
|
attr: str
|
|
35
37
|
|
|
36
38
|
|
|
@@ -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)}"
|
|
@@ -84,8 +86,11 @@ class QmodAnnotatedExpression:
|
|
|
84
86
|
self._concatenations: dict[QmodExprNodeId, ConcatenationAnnotation] = {}
|
|
85
87
|
self._locked = False
|
|
86
88
|
|
|
89
|
+
def print_by_node(self, node: ast.AST) -> str:
|
|
90
|
+
return ast.unparse(_ExprInliner(self).visit(node))
|
|
91
|
+
|
|
87
92
|
def __str__(self) -> str:
|
|
88
|
-
return
|
|
93
|
+
return self.print_by_node(self.root)
|
|
89
94
|
|
|
90
95
|
def has_node(self, node_id: QmodExprNodeId) -> bool:
|
|
91
96
|
return node_id in self._node_mapping
|
|
@@ -212,15 +217,13 @@ class QmodAnnotatedExpression:
|
|
|
212
217
|
def set_quantum_type_attr(
|
|
213
218
|
self,
|
|
214
219
|
node: Union[ast.AST, QmodExprNodeId],
|
|
215
|
-
value:
|
|
220
|
+
value: HandleBinding,
|
|
216
221
|
attr: str,
|
|
217
222
|
) -> None:
|
|
218
223
|
if self._locked:
|
|
219
224
|
raise ClassiqInternalExpansionError("QAE is locked")
|
|
220
225
|
if isinstance(node, ast.AST):
|
|
221
226
|
node = id(node)
|
|
222
|
-
if isinstance(value, ast.AST):
|
|
223
|
-
value = id(value)
|
|
224
227
|
self._quantum_type_attrs[node] = QuantumTypeAttributeAnnotation(
|
|
225
228
|
value=value, attr=attr
|
|
226
229
|
)
|
|
@@ -280,9 +283,7 @@ class QmodAnnotatedExpression:
|
|
|
280
283
|
if qs is not None:
|
|
281
284
|
self.clear_node_data(qs.value)
|
|
282
285
|
self.clear_node_data(qs.index)
|
|
283
|
-
|
|
284
|
-
if qta is not None:
|
|
285
|
-
self.clear_node_data(qta.value)
|
|
286
|
+
self._quantum_type_attrs.pop(node, None)
|
|
286
287
|
cnct = self._concatenations.pop(node, None)
|
|
287
288
|
if cnct is not None:
|
|
288
289
|
for element in cnct.elements:
|
|
@@ -85,7 +85,7 @@ class QmodExpressionEvaluator(ast.NodeVisitor):
|
|
|
85
85
|
Sequence[ClassicalFunctionDeclaration]
|
|
86
86
|
] = None,
|
|
87
87
|
classical_function_callables: Optional[Mapping[str, Callable]] = None,
|
|
88
|
-
scope: Optional[
|
|
88
|
+
scope: Optional[Mapping[str, Any]] = None,
|
|
89
89
|
) -> None:
|
|
90
90
|
self._expr_val = expr_val
|
|
91
91
|
self._treat_qnum_as_float = treat_qnum_as_float
|
|
@@ -264,7 +264,7 @@ def evaluate_qmod_expression(
|
|
|
264
264
|
Sequence[ClassicalFunctionDeclaration]
|
|
265
265
|
] = None,
|
|
266
266
|
classical_function_callables: Optional[Mapping[str, Callable]] = None,
|
|
267
|
-
scope: Optional[
|
|
267
|
+
scope: Optional[Mapping[str, Any]] = None,
|
|
268
268
|
) -> QmodAnnotatedExpression:
|
|
269
269
|
expr_ast = ast.parse(expr, mode="eval").body
|
|
270
270
|
expr_value = QmodAnnotatedExpression(expr_ast)
|
|
@@ -40,7 +40,7 @@ def replace_expression_type_attrs(
|
|
|
40
40
|
return expr_val
|
|
41
41
|
type_attrs = dict(expr_val.get_quantum_type_attributes())
|
|
42
42
|
for node_id, ta in type_attrs.items():
|
|
43
|
-
var =
|
|
43
|
+
var = ta.value
|
|
44
44
|
renamed_var = var
|
|
45
45
|
renamed_attr = ta.attr
|
|
46
46
|
for (source, attr), target in renaming.items():
|
|
@@ -5,6 +5,7 @@ from classiq.interface.exceptions import (
|
|
|
5
5
|
ClassiqExpansionError,
|
|
6
6
|
ClassiqInternalExpansionError,
|
|
7
7
|
)
|
|
8
|
+
from classiq.interface.generator.expressions.expression import Expression
|
|
8
9
|
from classiq.interface.generator.expressions.proxies.classical.qmod_struct_instance import (
|
|
9
10
|
QmodStructInstance,
|
|
10
11
|
)
|
|
@@ -15,7 +16,12 @@ from classiq.interface.generator.functions.classical_type import (
|
|
|
15
16
|
Integer,
|
|
16
17
|
)
|
|
17
18
|
from classiq.interface.generator.functions.type_name import TypeName
|
|
18
|
-
from classiq.interface.model.handle_binding import
|
|
19
|
+
from classiq.interface.model.handle_binding import (
|
|
20
|
+
FieldHandleBinding,
|
|
21
|
+
HandleBinding,
|
|
22
|
+
SlicedHandleBinding,
|
|
23
|
+
SubscriptHandleBinding,
|
|
24
|
+
)
|
|
19
25
|
from classiq.interface.model.quantum_type import (
|
|
20
26
|
QuantumBitvector,
|
|
21
27
|
QuantumNumeric,
|
|
@@ -26,6 +32,46 @@ from classiq.evaluators.qmod_annotated_expression import QmodAnnotatedExpression
|
|
|
26
32
|
from classiq.evaluators.qmod_node_evaluators.utils import QmodType
|
|
27
33
|
|
|
28
34
|
|
|
35
|
+
def _get_symbolic_quantum_var(
|
|
36
|
+
expr_val: QmodAnnotatedExpression, node: ast.AST
|
|
37
|
+
) -> HandleBinding:
|
|
38
|
+
if expr_val.has_quantum_var(node):
|
|
39
|
+
var = expr_val.get_var(node)
|
|
40
|
+
expr_val.remove_var(node)
|
|
41
|
+
return var
|
|
42
|
+
if isinstance(node, ast.Attribute):
|
|
43
|
+
return FieldHandleBinding(
|
|
44
|
+
base_handle=_get_symbolic_quantum_var(expr_val, node.value),
|
|
45
|
+
field=node.attr,
|
|
46
|
+
)
|
|
47
|
+
if isinstance(node, ast.Subscript):
|
|
48
|
+
base_var = _get_symbolic_quantum_var(expr_val, node.value)
|
|
49
|
+
slice_ = node.slice
|
|
50
|
+
if isinstance(slice_, ast.Slice):
|
|
51
|
+
if slice_.lower is None or slice_.upper is None or slice_.step is not None:
|
|
52
|
+
raise ClassiqInternalExpansionError("Illegal slice")
|
|
53
|
+
return SlicedHandleBinding(
|
|
54
|
+
base_handle=base_var,
|
|
55
|
+
start=Expression(expr=expr_val.print_by_node(slice_.lower)),
|
|
56
|
+
end=Expression(expr=expr_val.print_by_node(slice_.upper)),
|
|
57
|
+
)
|
|
58
|
+
else:
|
|
59
|
+
return SubscriptHandleBinding(
|
|
60
|
+
base_handle=base_var,
|
|
61
|
+
index=Expression(expr=expr_val.print_by_node(slice_)),
|
|
62
|
+
)
|
|
63
|
+
raise ClassiqInternalExpansionError("Symbolic variable construction failed")
|
|
64
|
+
|
|
65
|
+
|
|
66
|
+
def _remove_quantum_var(expr_val: QmodAnnotatedExpression, node: ast.AST) -> None:
|
|
67
|
+
if expr_val.has_quantum_var(node):
|
|
68
|
+
expr_val.remove_var(node)
|
|
69
|
+
elif isinstance(node, (ast.Attribute, ast.Subscript)):
|
|
70
|
+
_remove_quantum_var(expr_val, node.value)
|
|
71
|
+
else:
|
|
72
|
+
raise ClassiqInternalExpansionError("Failed to remove quantum var")
|
|
73
|
+
|
|
74
|
+
|
|
29
75
|
def _eval_type_attribute(
|
|
30
76
|
expr_val: QmodAnnotatedExpression, node: ast.Attribute
|
|
31
77
|
) -> None:
|
|
@@ -37,15 +83,22 @@ def _eval_type_attribute(
|
|
|
37
83
|
expr_val.set_type(node, Integer())
|
|
38
84
|
if subject_type.has_size_in_bits:
|
|
39
85
|
expr_val.set_value(node, subject_type.size_in_bits)
|
|
86
|
+
_remove_quantum_var(expr_val, subject)
|
|
40
87
|
else:
|
|
41
|
-
expr_val.set_quantum_type_attr(
|
|
88
|
+
expr_val.set_quantum_type_attr(
|
|
89
|
+
node, _get_symbolic_quantum_var(expr_val, subject), attr
|
|
90
|
+
)
|
|
42
91
|
return
|
|
43
92
|
if isinstance(subject_type, (ClassicalArray, QuantumBitvector)) and attr == "len":
|
|
44
93
|
expr_val.set_type(node, Integer())
|
|
45
94
|
if subject_type.has_constant_length:
|
|
46
95
|
expr_val.set_value(node, subject_type.length_value)
|
|
96
|
+
if isinstance(subject_type, QuantumBitvector):
|
|
97
|
+
_remove_quantum_var(expr_val, subject)
|
|
47
98
|
elif isinstance(subject_type, QuantumType):
|
|
48
|
-
expr_val.set_quantum_type_attr(
|
|
99
|
+
expr_val.set_quantum_type_attr(
|
|
100
|
+
node, _get_symbolic_quantum_var(expr_val, subject), attr
|
|
101
|
+
)
|
|
49
102
|
return
|
|
50
103
|
if isinstance(subject_type, ClassicalTuple) and attr == "len":
|
|
51
104
|
expr_val.set_type(node, Integer())
|
|
@@ -56,19 +109,27 @@ def _eval_type_attribute(
|
|
|
56
109
|
expr_val.set_type(node, Bool())
|
|
57
110
|
if subject_type.has_sign:
|
|
58
111
|
expr_val.set_value(node, subject_type.sign_value)
|
|
112
|
+
_remove_quantum_var(expr_val, subject)
|
|
59
113
|
elif subject_type.has_size_in_bits:
|
|
60
114
|
expr_val.set_value(node, False)
|
|
115
|
+
_remove_quantum_var(expr_val, subject)
|
|
61
116
|
else:
|
|
62
|
-
expr_val.set_quantum_type_attr(
|
|
117
|
+
expr_val.set_quantum_type_attr(
|
|
118
|
+
node, _get_symbolic_quantum_var(expr_val, subject), attr
|
|
119
|
+
)
|
|
63
120
|
return
|
|
64
121
|
if attr == "fraction_digits":
|
|
65
122
|
expr_val.set_type(node, Integer())
|
|
66
123
|
if subject_type.has_fraction_digits:
|
|
67
124
|
expr_val.set_value(node, subject_type.fraction_digits_value)
|
|
125
|
+
_remove_quantum_var(expr_val, subject)
|
|
68
126
|
elif subject_type.has_size_in_bits:
|
|
69
127
|
expr_val.set_value(node, 0)
|
|
128
|
+
_remove_quantum_var(expr_val, subject)
|
|
70
129
|
else:
|
|
71
|
-
expr_val.set_quantum_type_attr(
|
|
130
|
+
expr_val.set_quantum_type_attr(
|
|
131
|
+
node, _get_symbolic_quantum_var(expr_val, subject), attr
|
|
132
|
+
)
|
|
72
133
|
return
|
|
73
134
|
raise ClassiqExpansionError(
|
|
74
135
|
f"{subject_type.raw_qmod_type_name} has no attribute {attr!r}"
|