classiq 0.89.0__py3-none-any.whl → 0.91.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 +31 -127
- classiq/evaluators/parameter_types.py +200 -104
- classiq/evaluators/qmod_annotated_expression.py +3 -1
- classiq/evaluators/qmod_expression_visitors/qmod_expression_simplifier.py +10 -3
- 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 -8
- 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/executor/result.py +22 -3
- 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 +10 -22
- classiq/interface/generator/expressions/proxies/classical/classical_array_proxy.py +3 -8
- 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 +2 -5
- classiq/interface/generator/functions/concrete_types.py +1 -1
- classiq/interface/generator/functions/type_name.py +0 -12
- 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 -40
- classiq/interface/server/routes.py +2 -3
- classiq/model_expansions/capturing/captured_vars.py +10 -3
- classiq/model_expansions/closure.py +8 -0
- classiq/model_expansions/function_builder.py +18 -2
- classiq/model_expansions/interpreters/base_interpreter.py +84 -22
- classiq/model_expansions/interpreters/frontend_generative_interpreter.py +1 -11
- classiq/model_expansions/interpreters/generative_interpreter.py +67 -20
- 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 +50 -70
- classiq/model_expansions/quantum_operations/expression_evaluator.py +62 -7
- 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 +39 -41
- classiq/model_expansions/scope_initialization.py +3 -6
- classiq/model_expansions/transformers/model_renamer.py +35 -64
- classiq/model_expansions/transformers/type_modifier_inference.py +6 -6
- classiq/model_expansions/utils/handles_collector.py +7 -0
- 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 +42 -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 +18 -19
- classiq/qmod/quantum_expandable.py +1 -1
- classiq/qmod/semantics/error_manager.py +34 -15
- classiq/qmod/symbolic.py +15 -4
- classiq/qmod/utilities.py +4 -1
- classiq/synthesis.py +38 -3
- classiq/visualization.py +1 -1
- {classiq-0.89.0.dist-info → classiq-0.91.0.dist-info}/METADATA +1 -1
- {classiq-0.89.0.dist-info → classiq-0.91.0.dist-info}/RECORD +89 -107
- 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/interface/generator/expressions/handle_identifier.py +0 -6
- classiq/interface/generator/expressions/proxies/classical/any_classical_value.py +0 -41
- classiq/interface/generator/expressions/proxies/quantum/__init__.py +0 -0
- classiq/interface/generator/expressions/proxies/quantum/qmod_qarray_proxy.py +0 -80
- classiq/interface/generator/expressions/proxies/quantum/qmod_qscalar_proxy.py +0 -77
- classiq/interface/generator/expressions/proxies/quantum/qmod_qstruct_proxy.py +0 -38
- classiq/interface/generator/expressions/proxies/quantum/qmod_sized_proxy.py +0 -39
- classiq/interface/generator/expressions/type_proxy.py +0 -10
- classiq/model_expansions/atomic_expression_functions_defs.py +0 -413
- classiq/model_expansions/model_tables.py +0 -18
- classiq/model_expansions/sympy_conversion/__init__.py +0 -0
- classiq/model_expansions/sympy_conversion/expression_to_sympy.py +0 -181
- classiq/model_expansions/sympy_conversion/sympy_to_python.py +0 -132
- classiq/model_expansions/transformers/ast_renamer.py +0 -26
- classiq/model_expansions/utils/sympy_utils.py +0 -24
- {classiq-0.89.0.dist-info → classiq-0.91.0.dist-info}/WHEEL +0 -0
|
@@ -1,29 +1,18 @@
|
|
|
1
1
|
from collections.abc import Sequence
|
|
2
2
|
from itertools import chain, combinations
|
|
3
3
|
from typing import (
|
|
4
|
-
Any,
|
|
5
4
|
Generic,
|
|
6
5
|
Optional,
|
|
7
6
|
cast,
|
|
8
7
|
)
|
|
9
8
|
from uuid import UUID
|
|
10
9
|
|
|
11
|
-
import sympy
|
|
12
|
-
|
|
13
10
|
from classiq.interface.debug_info.debug_info import (
|
|
14
11
|
FunctionDebugInfo,
|
|
15
12
|
calculate_port_to_passed_variable_mapping,
|
|
13
|
+
new_function_debug_info_by_node,
|
|
16
14
|
)
|
|
17
15
|
from classiq.interface.exceptions import ClassiqExpansionError
|
|
18
|
-
from classiq.interface.generator.expressions.proxies.classical.any_classical_value import (
|
|
19
|
-
AnyClassicalValue,
|
|
20
|
-
)
|
|
21
|
-
from classiq.interface.generator.expressions.proxies.classical.classical_proxy import (
|
|
22
|
-
ClassicalProxy,
|
|
23
|
-
)
|
|
24
|
-
from classiq.interface.generator.expressions.proxies.classical.qmod_struct_instance import (
|
|
25
|
-
QmodStructInstance,
|
|
26
|
-
)
|
|
27
16
|
from classiq.interface.generator.functions.port_declaration import (
|
|
28
17
|
PortDeclarationDirection,
|
|
29
18
|
)
|
|
@@ -31,6 +20,7 @@ from classiq.interface.generator.functions.type_modifier import TypeModifier
|
|
|
31
20
|
from classiq.interface.generator.types.compilation_metadata import CompilationMetadata
|
|
32
21
|
from classiq.interface.helpers.backward_compatibility import zip_strict
|
|
33
22
|
from classiq.interface.helpers.text_utils import are, readable_list, s
|
|
23
|
+
from classiq.interface.model.block import Block
|
|
34
24
|
from classiq.interface.model.classical_parameter_declaration import (
|
|
35
25
|
ClassicalParameterDeclaration,
|
|
36
26
|
)
|
|
@@ -56,6 +46,7 @@ from classiq.evaluators.argument_types import (
|
|
|
56
46
|
from classiq.evaluators.parameter_types import (
|
|
57
47
|
evaluate_parameter_types_from_args,
|
|
58
48
|
)
|
|
49
|
+
from classiq.evaluators.qmod_annotated_expression import QmodAnnotatedExpression
|
|
59
50
|
from classiq.model_expansions.capturing.captured_vars import (
|
|
60
51
|
INITIALIZED_VAR_MESSAGE,
|
|
61
52
|
UNINITIALIZED_VAR_MESSAGE,
|
|
@@ -73,6 +64,7 @@ from classiq.model_expansions.quantum_operations.function_calls_cache import (
|
|
|
73
64
|
get_func_call_cache_key,
|
|
74
65
|
)
|
|
75
66
|
from classiq.model_expansions.scope import (
|
|
67
|
+
ClassicalSymbol,
|
|
76
68
|
Evaluated,
|
|
77
69
|
QuantumSymbol,
|
|
78
70
|
QuantumSymbolList,
|
|
@@ -111,18 +103,6 @@ def _validate_cloning(evaluated_args: list[Evaluated]) -> None:
|
|
|
111
103
|
)
|
|
112
104
|
|
|
113
105
|
|
|
114
|
-
def _is_symbolic(arg: Any) -> bool:
|
|
115
|
-
if isinstance(arg, (ClassicalProxy, AnyClassicalValue)):
|
|
116
|
-
return True
|
|
117
|
-
if isinstance(arg, list):
|
|
118
|
-
return any(_is_symbolic(item) for item in arg)
|
|
119
|
-
if isinstance(arg, QmodStructInstance):
|
|
120
|
-
return any(_is_symbolic(item) for item in arg.fields.values())
|
|
121
|
-
if isinstance(arg, sympy.Basic):
|
|
122
|
-
return len(arg.free_symbols) > 0
|
|
123
|
-
return False
|
|
124
|
-
|
|
125
|
-
|
|
126
106
|
def _validate_gen_args(
|
|
127
107
|
function: FunctionClosure, evaluated_args: list[Evaluated]
|
|
128
108
|
) -> None:
|
|
@@ -132,7 +112,7 @@ def _validate_gen_args(
|
|
|
132
112
|
if (
|
|
133
113
|
isinstance(param, ClassicalParameterDeclaration)
|
|
134
114
|
and not param.classical_type.is_purely_declarative
|
|
135
|
-
and
|
|
115
|
+
and isinstance(arg.value, QmodAnnotatedExpression)
|
|
136
116
|
):
|
|
137
117
|
readable_expr = transform_expression(str(arg.value), {}, {}, one_line=True)
|
|
138
118
|
raise ClassiqExpansionError(
|
|
@@ -141,6 +121,27 @@ def _validate_gen_args(
|
|
|
141
121
|
)
|
|
142
122
|
|
|
143
123
|
|
|
124
|
+
def _validate_runtime_args(args: list[Evaluated], scope: Scope) -> None:
|
|
125
|
+
for arg in args:
|
|
126
|
+
arg_val = arg.value
|
|
127
|
+
if not isinstance(arg_val, QmodAnnotatedExpression):
|
|
128
|
+
continue
|
|
129
|
+
classical_vars = dict.fromkeys(
|
|
130
|
+
var.name for var in arg_val.get_classical_vars().values()
|
|
131
|
+
)
|
|
132
|
+
runtime_classical_vars = [
|
|
133
|
+
var
|
|
134
|
+
for var in classical_vars
|
|
135
|
+
if isinstance(scope[var].value, ClassicalSymbol)
|
|
136
|
+
]
|
|
137
|
+
if len(runtime_classical_vars) > 0:
|
|
138
|
+
raise ClassiqExpansionError(
|
|
139
|
+
f"Passing runtime variable{s(runtime_classical_vars)} "
|
|
140
|
+
f"{readable_list(runtime_classical_vars, quote=True)} as function call "
|
|
141
|
+
f"arguments is not supported"
|
|
142
|
+
)
|
|
143
|
+
|
|
144
|
+
|
|
144
145
|
class CallEmitter(Generic[QuantumStatementT], Emitter[QuantumStatementT], ModelRenamer):
|
|
145
146
|
@staticmethod
|
|
146
147
|
def _should_wrap(body: Sequence[QuantumStatement]) -> bool:
|
|
@@ -148,6 +149,11 @@ class CallEmitter(Generic[QuantumStatementT], Emitter[QuantumStatementT], ModelR
|
|
|
148
149
|
# I'm sure there are better ways to handle it, but this is the simplest way to do it for now
|
|
149
150
|
return any(isinstance(stmt, VariableDeclarationStatement) for stmt in body)
|
|
150
151
|
|
|
152
|
+
def _create_block_labeled_ref(self, label: str) -> FunctionDebugInfo:
|
|
153
|
+
bake_ref_node = Block(statements=[], label=label)
|
|
154
|
+
self._interpreter.add_to_debug_info(statement=bake_ref_node)
|
|
155
|
+
return new_function_debug_info_by_node(bake_ref_node)
|
|
156
|
+
|
|
151
157
|
def _create_expanded_wrapping_function(
|
|
152
158
|
self,
|
|
153
159
|
name: str,
|
|
@@ -195,6 +201,7 @@ class CallEmitter(Generic[QuantumStatementT], Emitter[QuantumStatementT], ModelR
|
|
|
195
201
|
self._validate_call_args(function.positional_arg_declarations, args)
|
|
196
202
|
evaluated_args = [self._interpreter.evaluate(arg) for arg in args]
|
|
197
203
|
_validate_cloning(evaluated_args)
|
|
204
|
+
_validate_runtime_args(evaluated_args, self._current_scope)
|
|
198
205
|
new_declaration = self._prepare_fully_typed_declaration(
|
|
199
206
|
function, evaluated_args
|
|
200
207
|
)
|
|
@@ -385,7 +392,6 @@ class CallEmitter(Generic[QuantumStatementT], Emitter[QuantumStatementT], ModelR
|
|
|
385
392
|
name=function.name,
|
|
386
393
|
positional_arg_declarations=evaluate_parameter_types_from_args(
|
|
387
394
|
function,
|
|
388
|
-
function.signature_scope,
|
|
389
395
|
evaluated_args,
|
|
390
396
|
),
|
|
391
397
|
)
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import re
|
|
2
2
|
|
|
3
|
+
from classiq.interface.exceptions import ClassiqExpansionError
|
|
3
4
|
from classiq.interface.model.handle_binding import HandleBinding
|
|
4
5
|
from classiq.interface.model.quantum_expressions.arithmetic_operation import (
|
|
5
6
|
ArithmeticOperation,
|
|
@@ -14,9 +15,12 @@ class ClassicalVarEmitter(Emitter[ArithmeticOperation]):
|
|
|
14
15
|
result_symbol = self._interpreter.evaluate(op.result_var).value
|
|
15
16
|
if not isinstance(result_symbol, ClassicalSymbol):
|
|
16
17
|
return False
|
|
17
|
-
op.
|
|
18
|
+
op.classical_assignment = True
|
|
18
19
|
match = re.search(r"measure\((.*?)\)", op.expression.expr)
|
|
19
20
|
if match is not None:
|
|
20
|
-
|
|
21
|
+
var = match.group(1)
|
|
22
|
+
if "[" in var or "." in var:
|
|
23
|
+
raise ClassiqExpansionError("'measure' must receive a whole variable")
|
|
24
|
+
op.set_var_handles([HandleBinding(name=var)])
|
|
21
25
|
self.emit_statement(op)
|
|
22
26
|
return True
|
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
import ast
|
|
2
1
|
from abc import ABC, abstractmethod
|
|
3
2
|
from collections.abc import Sequence
|
|
4
3
|
from typing import (
|
|
@@ -9,17 +8,10 @@ from typing import (
|
|
|
9
8
|
Union,
|
|
10
9
|
)
|
|
11
10
|
|
|
12
|
-
import sympy
|
|
13
|
-
|
|
14
11
|
from classiq.interface.debug_info.debug_info import (
|
|
15
12
|
DebugInfoCollection,
|
|
16
13
|
)
|
|
17
14
|
from classiq.interface.exceptions import ClassiqInternalExpansionError
|
|
18
|
-
from classiq.interface.generator.expressions.atomic_expression_functions import (
|
|
19
|
-
CLASSICAL_ATTRIBUTES,
|
|
20
|
-
SUPPORTED_CLASSIQ_BUILTIN_FUNCTIONS,
|
|
21
|
-
SUPPORTED_PYTHON_BUILTIN_FUNCTIONS,
|
|
22
|
-
)
|
|
23
15
|
from classiq.interface.generator.expressions.evaluated_expression import (
|
|
24
16
|
EvaluatedExpression,
|
|
25
17
|
)
|
|
@@ -47,17 +39,14 @@ from classiq.interface.model.quantum_function_declaration import (
|
|
|
47
39
|
)
|
|
48
40
|
from classiq.interface.model.quantum_statement import QuantumOperation, QuantumStatement
|
|
49
41
|
|
|
42
|
+
from classiq.evaluators.qmod_annotated_expression import QmodAnnotatedExpression
|
|
50
43
|
from classiq.model_expansions.closure import Closure, FunctionClosure, GenerativeClosure
|
|
51
44
|
from classiq.model_expansions.function_builder import (
|
|
52
45
|
OperationBuilder,
|
|
53
46
|
OperationContext,
|
|
54
47
|
)
|
|
55
|
-
from classiq.model_expansions.scope import QuantumSymbol, Scope
|
|
56
|
-
from classiq.model_expansions.sympy_conversion.sympy_to_python import (
|
|
57
|
-
translate_sympy_quantum_expression,
|
|
58
|
-
)
|
|
48
|
+
from classiq.model_expansions.scope import ClassicalSymbol, QuantumSymbol, Scope
|
|
59
49
|
from classiq.model_expansions.utils.counted_name_allocator import CountedNameAllocator
|
|
60
|
-
from classiq.model_expansions.visitors.variable_references import VarRefCollector
|
|
61
50
|
from classiq.qmod.quantum_function import GenerativeQFunc
|
|
62
51
|
|
|
63
52
|
if TYPE_CHECKING:
|
|
@@ -153,22 +142,18 @@ class Emitter(Generic[QuantumStatementT], ABC):
|
|
|
153
142
|
return context
|
|
154
143
|
|
|
155
144
|
def _evaluate_expression(
|
|
156
|
-
self,
|
|
145
|
+
self,
|
|
146
|
+
expression: Expression,
|
|
147
|
+
*,
|
|
148
|
+
simplify: bool = False,
|
|
149
|
+
treat_qnum_as_float: bool = False,
|
|
157
150
|
) -> Expression:
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
)
|
|
165
|
-
)
|
|
166
|
-
else:
|
|
167
|
-
new_expression = Expression(expr=str(evaluated_expression.value))
|
|
168
|
-
new_expression._evaluated_expr = EvaluatedExpression(
|
|
169
|
-
value=evaluated_expression.value
|
|
170
|
-
)
|
|
171
|
-
return new_expression
|
|
151
|
+
expr_val = self._interpreter.evaluate(
|
|
152
|
+
expression, simplify=simplify, treat_qnum_as_float=treat_qnum_as_float
|
|
153
|
+
).value
|
|
154
|
+
new_expr = Expression(expr=str(expr_val))
|
|
155
|
+
new_expr._evaluated_expr = EvaluatedExpression(value=expr_val)
|
|
156
|
+
return new_expr
|
|
172
157
|
|
|
173
158
|
def emit_statement(self, statement: QuantumStatement) -> None:
|
|
174
159
|
self._update_captured_classical_vars(statement)
|
|
@@ -196,10 +181,8 @@ class Emitter(Generic[QuantumStatementT], ABC):
|
|
|
196
181
|
) -> None:
|
|
197
182
|
if handle.name not in self._current_scope:
|
|
198
183
|
return
|
|
199
|
-
|
|
200
|
-
self._update_captured_classical_vars_in_expression(
|
|
201
|
-
Expression(expr=str(handle))
|
|
202
|
-
)
|
|
184
|
+
for expr in handle.expressions():
|
|
185
|
+
self._update_captured_classical_vars_in_expression(expr)
|
|
203
186
|
while isinstance(handle, NestedHandleBinding) and not handle.is_constant():
|
|
204
187
|
handle = handle.base_handle
|
|
205
188
|
defining_function = self._current_scope[handle.name].defining_function
|
|
@@ -237,52 +220,49 @@ class Emitter(Generic[QuantumStatementT], ABC):
|
|
|
237
220
|
)
|
|
238
221
|
|
|
239
222
|
def _get_symbols_in_expression(self, expr: Expression) -> list[QuantumSymbol]:
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
handle
|
|
244
|
-
for handle in vrc.var_handles
|
|
245
|
-
if handle.name
|
|
246
|
-
not in SUPPORTED_PYTHON_BUILTIN_FUNCTIONS
|
|
247
|
-
| SUPPORTED_CLASSIQ_BUILTIN_FUNCTIONS
|
|
248
|
-
and isinstance(self._current_scope[handle.name].value, QuantumSymbol)
|
|
249
|
-
)
|
|
223
|
+
expr_val = expr.value.value
|
|
224
|
+
if not isinstance(expr_val, QmodAnnotatedExpression):
|
|
225
|
+
return []
|
|
250
226
|
return [
|
|
251
|
-
|
|
252
|
-
for
|
|
253
|
-
if not isinstance(handle, FieldHandleBinding)
|
|
254
|
-
or handle.field not in CLASSICAL_ATTRIBUTES
|
|
227
|
+
QuantumSymbol(handle=var, quantum_type=expr_val.get_quantum_type(node_id))
|
|
228
|
+
for node_id, var in expr_val.get_quantum_vars().items()
|
|
255
229
|
]
|
|
256
230
|
|
|
257
231
|
def _get_classical_vars_in_expression(
|
|
258
232
|
self, expr: Expression
|
|
259
233
|
) -> list[tuple[str, ClassicalType]]:
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
for handle in vrc.var_handles
|
|
268
|
-
if handle.name in self._current_scope
|
|
269
|
-
and isinstance(
|
|
270
|
-
proxy := self._current_scope[handle.name].value, ClassicalProxy
|
|
271
|
-
)
|
|
272
|
-
}.items()
|
|
234
|
+
if not expr.is_evaluated():
|
|
235
|
+
raise ClassiqInternalExpansionError
|
|
236
|
+
expr_val = expr.value.value
|
|
237
|
+
if not isinstance(expr_val, QmodAnnotatedExpression):
|
|
238
|
+
return []
|
|
239
|
+
classical_vars = list(
|
|
240
|
+
dict.fromkeys(var.name for var in expr_val.get_classical_vars().values())
|
|
273
241
|
)
|
|
242
|
+
return [
|
|
243
|
+
(
|
|
244
|
+
var,
|
|
245
|
+
(
|
|
246
|
+
get_proxy_type(proxy)
|
|
247
|
+
if isinstance(proxy, ClassicalProxy)
|
|
248
|
+
else proxy.classical_type
|
|
249
|
+
),
|
|
250
|
+
)
|
|
251
|
+
for var in classical_vars
|
|
252
|
+
if var in self._current_scope
|
|
253
|
+
and isinstance(
|
|
254
|
+
proxy := self._current_scope[var].value,
|
|
255
|
+
(ClassicalProxy, ClassicalSymbol),
|
|
256
|
+
)
|
|
257
|
+
]
|
|
274
258
|
|
|
275
259
|
def _get_quantum_type_attributes_in_expression(
|
|
276
260
|
self, expr: Expression
|
|
277
261
|
) -> list[FieldHandleBinding]:
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
and handle.field in CLASSICAL_ATTRIBUTES
|
|
286
|
-
and isinstance(self._current_scope[handle.name].value, QuantumSymbol)
|
|
287
|
-
)
|
|
288
|
-
)
|
|
262
|
+
expr_val = expr.value.value
|
|
263
|
+
if not isinstance(expr_val, QmodAnnotatedExpression):
|
|
264
|
+
return []
|
|
265
|
+
return [
|
|
266
|
+
FieldHandleBinding(base_handle=type_attr.value, field=type_attr.attr)
|
|
267
|
+
for type_attr in expr_val.get_quantum_type_attributes().values()
|
|
268
|
+
]
|
|
@@ -1,38 +1,93 @@
|
|
|
1
|
-
from typing import TYPE_CHECKING
|
|
1
|
+
from typing import TYPE_CHECKING, Optional
|
|
2
2
|
|
|
3
|
+
from classiq.interface.exceptions import (
|
|
4
|
+
ClassiqExpansionError,
|
|
5
|
+
ClassiqInternalExpansionError,
|
|
6
|
+
)
|
|
3
7
|
from classiq.interface.generator.expressions.expression import Expression
|
|
4
8
|
from classiq.interface.generator.functions.port_declaration import (
|
|
5
9
|
PortDeclarationDirection,
|
|
6
10
|
)
|
|
11
|
+
from classiq.interface.helpers.text_utils import readable_list, s
|
|
7
12
|
from classiq.interface.model.quantum_statement import QuantumOperation
|
|
8
13
|
|
|
9
14
|
from classiq.model_expansions.quantum_operations.emitter import Emitter
|
|
15
|
+
from classiq.model_expansions.scope import ClassicalSymbol
|
|
10
16
|
|
|
11
17
|
if TYPE_CHECKING:
|
|
12
18
|
from classiq.model_expansions.interpreters.base_interpreter import BaseInterpreter
|
|
13
19
|
|
|
14
20
|
|
|
15
21
|
class ExpressionEvaluator(Emitter[QuantumOperation]):
|
|
16
|
-
def __init__(
|
|
22
|
+
def __init__(
|
|
23
|
+
self,
|
|
24
|
+
interpreter: "BaseInterpreter",
|
|
25
|
+
expression_name: str,
|
|
26
|
+
*,
|
|
27
|
+
readable_expression_name: Optional[str] = None,
|
|
28
|
+
simplify: bool = False,
|
|
29
|
+
treat_qnum_as_float: bool = False,
|
|
30
|
+
allow_link_time_vars: bool = True,
|
|
31
|
+
allow_runtime_vars: bool = True,
|
|
32
|
+
) -> None:
|
|
17
33
|
super().__init__(interpreter)
|
|
18
34
|
self._expression_name = expression_name
|
|
35
|
+
self._simplify = simplify
|
|
36
|
+
self._treat_qnum_as_float = treat_qnum_as_float
|
|
37
|
+
self._allow_link_time_vars = allow_link_time_vars
|
|
38
|
+
self._allow_runtime_vars = allow_runtime_vars
|
|
39
|
+
if (
|
|
40
|
+
not allow_link_time_vars or not allow_runtime_vars
|
|
41
|
+
) and readable_expression_name is None:
|
|
42
|
+
raise ClassiqInternalExpansionError
|
|
43
|
+
self._readable_expression_name = readable_expression_name
|
|
19
44
|
|
|
20
45
|
def emit(self, op: QuantumOperation, /) -> bool:
|
|
21
46
|
expression = getattr(op, self._expression_name)
|
|
22
47
|
if not isinstance(expression, Expression) or expression.is_evaluated():
|
|
23
48
|
return False
|
|
24
49
|
evaluated_expression = self._evaluate_expression(
|
|
25
|
-
expression,
|
|
50
|
+
expression,
|
|
51
|
+
simplify=self._simplify,
|
|
52
|
+
treat_qnum_as_float=self._treat_qnum_as_float,
|
|
26
53
|
)
|
|
27
54
|
for symbol in self._get_symbols_in_expression(evaluated_expression):
|
|
28
55
|
self._capture_handle(symbol.handle, PortDeclarationDirection.Inout)
|
|
29
|
-
|
|
30
|
-
evaluated_expression
|
|
31
|
-
):
|
|
32
|
-
self._capture_classical_var(var_name, var_type)
|
|
56
|
+
self._process_classical_parameters(evaluated_expression)
|
|
33
57
|
op = op.model_copy(
|
|
34
58
|
update={self._expression_name: evaluated_expression, "back_ref": op.uuid}
|
|
35
59
|
)
|
|
36
60
|
self._interpreter.add_to_debug_info(op)
|
|
37
61
|
self._interpreter.emit(op)
|
|
38
62
|
return True
|
|
63
|
+
|
|
64
|
+
def _process_classical_parameters(self, evaluated_expression: Expression) -> None:
|
|
65
|
+
link_time_vars: list[str] = []
|
|
66
|
+
runtime_vars: list[str] = []
|
|
67
|
+
for var_name, var_type in self._get_classical_vars_in_expression(
|
|
68
|
+
evaluated_expression
|
|
69
|
+
):
|
|
70
|
+
if isinstance(self._current_scope[var_name].value, ClassicalSymbol):
|
|
71
|
+
runtime_vars.append(var_name)
|
|
72
|
+
else:
|
|
73
|
+
link_time_vars.append(var_name)
|
|
74
|
+
self._capture_classical_var(var_name, var_type)
|
|
75
|
+
if not self._allow_link_time_vars and len(link_time_vars) > 0:
|
|
76
|
+
link_time_message = f"link-time variable{s(link_time_vars)} {readable_list(link_time_vars, quote=True)}"
|
|
77
|
+
else:
|
|
78
|
+
link_time_message = None
|
|
79
|
+
if not self._allow_runtime_vars and len(runtime_vars) > 0:
|
|
80
|
+
runtime_message = f"runtime variable{s(runtime_vars)} {readable_list(runtime_vars, quote=True)}"
|
|
81
|
+
else:
|
|
82
|
+
runtime_message = None
|
|
83
|
+
if link_time_message is None:
|
|
84
|
+
error_message = runtime_message
|
|
85
|
+
elif runtime_message is None:
|
|
86
|
+
error_message = link_time_message
|
|
87
|
+
else:
|
|
88
|
+
error_message = f"{link_time_message} and {runtime_message}"
|
|
89
|
+
if error_message is not None:
|
|
90
|
+
raise ClassiqExpansionError(
|
|
91
|
+
f"The {self._readable_expression_name} cannot receive "
|
|
92
|
+
f"{error_message}"
|
|
93
|
+
)
|
|
@@ -1,7 +1,5 @@
|
|
|
1
1
|
from typing import TYPE_CHECKING
|
|
2
2
|
|
|
3
|
-
import sympy
|
|
4
|
-
|
|
5
3
|
from classiq.interface.exceptions import ClassiqInternalExpansionError
|
|
6
4
|
from classiq.interface.generator.expressions.expression import Expression
|
|
7
5
|
from classiq.interface.model.classical_if import ClassicalIf
|
|
@@ -9,6 +7,7 @@ from classiq.interface.model.quantum_function_call import QuantumFunctionCall
|
|
|
9
7
|
from classiq.interface.model.quantum_lambda_function import OperandIdentifier
|
|
10
8
|
from classiq.interface.model.quantum_statement import QuantumStatement
|
|
11
9
|
|
|
10
|
+
from classiq.evaluators.qmod_annotated_expression import QmodAnnotatedExpression
|
|
12
11
|
from classiq.model_expansions.closure import FunctionClosure
|
|
13
12
|
from classiq.model_expansions.quantum_operations.call_emitter import CallEmitter
|
|
14
13
|
from classiq.model_expansions.quantum_operations.declarative_call_emitter import (
|
|
@@ -28,7 +27,7 @@ class QuantumFunctionCallEmitter(CallEmitter[QuantumFunctionCall]):
|
|
|
28
27
|
def emit(self, call: QuantumFunctionCall, /) -> bool:
|
|
29
28
|
if isinstance(call.function, OperandIdentifier):
|
|
30
29
|
index_val = self._interpreter.evaluate(call.function.index).value
|
|
31
|
-
if isinstance(index_val,
|
|
30
|
+
if isinstance(index_val, QmodAnnotatedExpression):
|
|
32
31
|
return self._emit_symbolic_lambda_list(call, index_val)
|
|
33
32
|
function = self._interpreter.evaluate(call.function).as_type(FunctionClosure)
|
|
34
33
|
args = call.positional_args
|
|
@@ -39,7 +38,7 @@ class QuantumFunctionCallEmitter(CallEmitter[QuantumFunctionCall]):
|
|
|
39
38
|
return True
|
|
40
39
|
|
|
41
40
|
def _emit_symbolic_lambda_list(
|
|
42
|
-
self, call: QuantumFunctionCall, index:
|
|
41
|
+
self, call: QuantumFunctionCall, index: QmodAnnotatedExpression
|
|
43
42
|
) -> bool:
|
|
44
43
|
if TYPE_CHECKING:
|
|
45
44
|
assert isinstance(call.function, OperandIdentifier)
|
|
@@ -54,7 +53,7 @@ class QuantumFunctionCallEmitter(CallEmitter[QuantumFunctionCall]):
|
|
|
54
53
|
|
|
55
54
|
@staticmethod
|
|
56
55
|
def _create_recursive_if(
|
|
57
|
-
call: QuantumFunctionCall, index:
|
|
56
|
+
call: QuantumFunctionCall, index: QmodAnnotatedExpression, num_funcs: int
|
|
58
57
|
) -> list[QuantumStatement]:
|
|
59
58
|
if TYPE_CHECKING:
|
|
60
59
|
assert isinstance(call.function, OperandIdentifier)
|
|
@@ -1,7 +1,8 @@
|
|
|
1
|
-
from typing import TYPE_CHECKING, Union
|
|
1
|
+
from typing import TYPE_CHECKING, Union, cast
|
|
2
2
|
|
|
3
3
|
from classiq.interface.exceptions import ClassiqExpansionError
|
|
4
4
|
from classiq.interface.generator.functions.classical_type import ClassicalType
|
|
5
|
+
from classiq.interface.generator.functions.concrete_types import ConcreteType
|
|
5
6
|
from classiq.interface.model.handle_binding import HandleBinding
|
|
6
7
|
from classiq.interface.model.quantum_type import QuantumType
|
|
7
8
|
from classiq.interface.model.variable_declaration_statement import (
|
|
@@ -30,13 +31,15 @@ class VariableDeclarationStatementEmitter(Emitter[VariableDeclarationStatement])
|
|
|
30
31
|
if variable_declaration.is_quantum:
|
|
31
32
|
if TYPE_CHECKING:
|
|
32
33
|
assert isinstance(var_decl.qmod_type, QuantumType)
|
|
34
|
+
updated_quantum_type = evaluate_type_in_quantum_symbol(
|
|
35
|
+
var_decl.qmod_type,
|
|
36
|
+
self._current_scope,
|
|
37
|
+
var_decl.name,
|
|
38
|
+
)
|
|
39
|
+
var_decl.qmod_type = updated_quantum_type
|
|
33
40
|
var_value = QuantumSymbol(
|
|
34
41
|
handle=HandleBinding(name=var_decl.name),
|
|
35
|
-
quantum_type=
|
|
36
|
-
var_decl.qmod_type,
|
|
37
|
-
self._current_scope,
|
|
38
|
-
var_decl.name,
|
|
39
|
-
),
|
|
42
|
+
quantum_type=updated_quantum_type,
|
|
40
43
|
)
|
|
41
44
|
self._builder.current_block.captured_vars.init_var(
|
|
42
45
|
var_decl.name, self._builder.current_function
|
|
@@ -44,13 +47,15 @@ class VariableDeclarationStatementEmitter(Emitter[VariableDeclarationStatement])
|
|
|
44
47
|
else:
|
|
45
48
|
if TYPE_CHECKING:
|
|
46
49
|
assert isinstance(var_decl.qmod_type, ClassicalType)
|
|
50
|
+
updated_classical_type = evaluate_type_in_classical_symbol(
|
|
51
|
+
var_decl.qmod_type,
|
|
52
|
+
self._current_scope,
|
|
53
|
+
var_decl.name,
|
|
54
|
+
)
|
|
55
|
+
var_decl.qmod_type = cast(ConcreteType, updated_classical_type)
|
|
47
56
|
var_value = ClassicalSymbol(
|
|
48
57
|
handle=HandleBinding(name=var_decl.name),
|
|
49
|
-
classical_type=
|
|
50
|
-
var_decl.qmod_type,
|
|
51
|
-
self._current_scope,
|
|
52
|
-
var_decl.name,
|
|
53
|
-
),
|
|
58
|
+
classical_type=updated_classical_type,
|
|
54
59
|
)
|
|
55
60
|
self._current_scope[variable_declaration.name] = Evaluated(
|
|
56
61
|
value=var_value, defining_function=self._builder.current_function
|