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,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
48
|
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
|
-
)
|
|
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,39 @@ 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
|
+
(var, get_proxy_type(proxy))
|
|
244
|
+
for var in classical_vars
|
|
245
|
+
if var in self._current_scope
|
|
246
|
+
and isinstance(proxy := self._current_scope[var].value, ClassicalProxy)
|
|
247
|
+
]
|
|
274
248
|
|
|
275
249
|
def _get_quantum_type_attributes_in_expression(
|
|
276
250
|
self, expr: Expression
|
|
277
251
|
) -> 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
|
-
)
|
|
252
|
+
expr_val = expr.value.value
|
|
253
|
+
if not isinstance(expr_val, QmodAnnotatedExpression):
|
|
254
|
+
return []
|
|
255
|
+
return [
|
|
256
|
+
FieldHandleBinding(base_handle=type_attr.value, field=type_attr.attr)
|
|
257
|
+
for type_attr in expr_val.get_quantum_type_attributes().values()
|
|
258
|
+
]
|
|
@@ -13,16 +13,27 @@ if TYPE_CHECKING:
|
|
|
13
13
|
|
|
14
14
|
|
|
15
15
|
class ExpressionEvaluator(Emitter[QuantumOperation]):
|
|
16
|
-
def __init__(
|
|
16
|
+
def __init__(
|
|
17
|
+
self,
|
|
18
|
+
interpreter: "BaseInterpreter",
|
|
19
|
+
expression_name: str,
|
|
20
|
+
*,
|
|
21
|
+
simplify: bool = False,
|
|
22
|
+
treat_qnum_as_float: bool = False,
|
|
23
|
+
) -> None:
|
|
17
24
|
super().__init__(interpreter)
|
|
18
25
|
self._expression_name = expression_name
|
|
26
|
+
self._simplify = simplify
|
|
27
|
+
self._treat_qnum_as_float = treat_qnum_as_float
|
|
19
28
|
|
|
20
29
|
def emit(self, op: QuantumOperation, /) -> bool:
|
|
21
30
|
expression = getattr(op, self._expression_name)
|
|
22
31
|
if not isinstance(expression, Expression) or expression.is_evaluated():
|
|
23
32
|
return False
|
|
24
33
|
evaluated_expression = self._evaluate_expression(
|
|
25
|
-
expression,
|
|
34
|
+
expression,
|
|
35
|
+
simplify=self._simplify,
|
|
36
|
+
treat_qnum_as_float=self._treat_qnum_as_float,
|
|
26
37
|
)
|
|
27
38
|
for symbol in self._get_symbols_in_expression(evaluated_expression):
|
|
28
39
|
self._capture_handle(symbol.handle, PortDeclarationDirection.Inout)
|
|
@@ -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
|
|
@@ -15,9 +15,6 @@ from classiq.interface.generator.expressions.evaluated_expression import (
|
|
|
15
15
|
EvaluatedExpression,
|
|
16
16
|
)
|
|
17
17
|
from classiq.interface.generator.expressions.expression import Expression
|
|
18
|
-
from classiq.interface.generator.expressions.proxies.classical.classical_scalar_proxy import (
|
|
19
|
-
ClassicalScalarProxy,
|
|
20
|
-
)
|
|
21
18
|
from classiq.interface.generator.expressions.proxies.classical.qmod_struct_instance import (
|
|
22
19
|
QmodStructInstance,
|
|
23
20
|
)
|
|
@@ -43,6 +40,9 @@ from classiq.interface.model.quantum_type import (
|
|
|
43
40
|
QuantumType,
|
|
44
41
|
)
|
|
45
42
|
|
|
43
|
+
from classiq.evaluators.qmod_annotated_expression import QmodAnnotatedExpression
|
|
44
|
+
from classiq.evaluators.qmod_node_evaluators.utils import get_sympy_val
|
|
45
|
+
|
|
46
46
|
if TYPE_CHECKING:
|
|
47
47
|
from classiq.model_expansions.closure import FunctionClosure
|
|
48
48
|
|
|
@@ -69,7 +69,7 @@ class QuantumSymbol(QuantumVariable):
|
|
|
69
69
|
return self.handle
|
|
70
70
|
|
|
71
71
|
def __getitem__(
|
|
72
|
-
self, item: Union[slice, int,
|
|
72
|
+
self, item: Union[slice, int, QmodAnnotatedExpression]
|
|
73
73
|
) -> "QuantumSymbol":
|
|
74
74
|
if isinstance(item, slice):
|
|
75
75
|
return self._slice(item.start, item.stop)
|
|
@@ -77,8 +77,8 @@ class QuantumSymbol(QuantumVariable):
|
|
|
77
77
|
|
|
78
78
|
def _slice(
|
|
79
79
|
self,
|
|
80
|
-
start: Union[int,
|
|
81
|
-
end: Union[int,
|
|
80
|
+
start: Union[int, QmodAnnotatedExpression],
|
|
81
|
+
end: Union[int, QmodAnnotatedExpression],
|
|
82
82
|
) -> "QuantumSymbol":
|
|
83
83
|
if not isinstance(self.quantum_type, QuantumBitvector):
|
|
84
84
|
raise ClassiqExpansionError(
|
|
@@ -100,19 +100,27 @@ class QuantumSymbol(QuantumVariable):
|
|
|
100
100
|
f"{self.quantum_type.type_name.lower()} {str(self.handle)!r} (of "
|
|
101
101
|
f"length {self.quantum_type.length_value})"
|
|
102
102
|
)
|
|
103
|
+
start_expr = Expression(expr=str(start))
|
|
104
|
+
start_expr._evaluated_expr = EvaluatedExpression(value=start)
|
|
105
|
+
end_expr = Expression(expr=str(end))
|
|
106
|
+
end_expr._evaluated_expr = EvaluatedExpression(value=end)
|
|
107
|
+
if isinstance(start, int) and isinstance(end, int):
|
|
108
|
+
length_expr = Expression(expr=str(end - start))
|
|
109
|
+
else:
|
|
110
|
+
length_expr = None
|
|
103
111
|
return QuantumSymbol(
|
|
104
112
|
handle=SlicedHandleBinding(
|
|
105
113
|
base_handle=self.handle,
|
|
106
|
-
start=
|
|
107
|
-
end=
|
|
114
|
+
start=start_expr,
|
|
115
|
+
end=end_expr,
|
|
108
116
|
),
|
|
109
117
|
quantum_type=QuantumBitvector(
|
|
110
118
|
element_type=self.quantum_type.element_type,
|
|
111
|
-
length=
|
|
119
|
+
length=length_expr,
|
|
112
120
|
),
|
|
113
121
|
)
|
|
114
122
|
|
|
115
|
-
def _subscript(self, index: Union[int,
|
|
123
|
+
def _subscript(self, index: Union[int, QmodAnnotatedExpression]) -> "QuantumSymbol":
|
|
116
124
|
if not isinstance(self.quantum_type, QuantumBitvector):
|
|
117
125
|
raise ClassiqExpansionError(
|
|
118
126
|
f"{self.quantum_type.type_name} is not subscriptable"
|
|
@@ -135,11 +143,10 @@ class QuantumSymbol(QuantumVariable):
|
|
|
135
143
|
f"{self.quantum_type.type_name.lower()} {str(self.handle)!r}"
|
|
136
144
|
f"{length_suffix}"
|
|
137
145
|
)
|
|
146
|
+
index_expr = Expression(expr=str(index))
|
|
147
|
+
index_expr._evaluated_expr = EvaluatedExpression(value=index)
|
|
138
148
|
return QuantumSymbol(
|
|
139
|
-
handle=SubscriptHandleBinding(
|
|
140
|
-
base_handle=self.handle,
|
|
141
|
-
index=Expression(expr=str(index)),
|
|
142
|
-
),
|
|
149
|
+
handle=SubscriptHandleBinding(base_handle=self.handle, index=index_expr),
|
|
143
150
|
quantum_type=self.quantum_type.element_type,
|
|
144
151
|
)
|
|
145
152
|
|
|
@@ -204,11 +211,15 @@ class QuantumSymbolList(QuantumVariable):
|
|
|
204
211
|
|
|
205
212
|
|
|
206
213
|
@dataclass(frozen=True)
|
|
207
|
-
class
|
|
208
|
-
handle: HandleBinding
|
|
214
|
+
class ClassicalVariable:
|
|
209
215
|
classical_type: ClassicalType
|
|
210
216
|
|
|
211
217
|
|
|
218
|
+
@dataclass(frozen=True)
|
|
219
|
+
class ClassicalSymbol(ClassicalVariable):
|
|
220
|
+
handle: HandleBinding
|
|
221
|
+
|
|
222
|
+
|
|
212
223
|
@singledispatch
|
|
213
224
|
def evaluated_to_str(value: Any) -> str:
|
|
214
225
|
return str(value)
|
|
@@ -225,8 +236,8 @@ def _evaluated_to_str_struct_literal(value: QmodStructInstance) -> str:
|
|
|
225
236
|
|
|
226
237
|
|
|
227
238
|
def _raise_type_error(val: Any, t: type, location_hint: Optional[str]) -> NoReturn:
|
|
228
|
-
if isinstance(val,
|
|
229
|
-
symbolic_vars = sorted(map(str, val.
|
|
239
|
+
if isinstance(val, QmodAnnotatedExpression) and len(val.get_classical_vars()) > 0:
|
|
240
|
+
symbolic_vars = sorted(map(str, val.get_classical_vars().values()))
|
|
230
241
|
suffix = f" {location_hint}" if location_hint is not None else ""
|
|
231
242
|
raise ClassiqExpansionError(
|
|
232
243
|
f"Cannot use execution parameter{s(symbolic_vars)} {readable_list(symbolic_vars, quote=True)} in a compile-time context{suffix}"
|
|
@@ -240,19 +251,15 @@ class Evaluated: # FIXME: Merge with EvaluatedExpression if possible
|
|
|
240
251
|
defining_function: Optional["FunctionClosure"] = None
|
|
241
252
|
|
|
242
253
|
def as_type(self, t: type[T], location_hint: Optional[str] = None) -> T:
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
if
|
|
254
|
+
value = self.value
|
|
255
|
+
if isinstance(value, sympy.Basic):
|
|
256
|
+
value = get_sympy_val(value)
|
|
257
|
+
if t is int and isinstance(value, float):
|
|
258
|
+
value = int(value)
|
|
259
|
+
if not isinstance(value, t):
|
|
247
260
|
_raise_type_error(self.value, t, location_hint)
|
|
248
261
|
|
|
249
|
-
return
|
|
250
|
-
|
|
251
|
-
def _as_int(self, location_hint: Optional[str]) -> int:
|
|
252
|
-
if not isinstance(self.value, (int, float)):
|
|
253
|
-
_raise_type_error(self.value, int, location_hint)
|
|
254
|
-
|
|
255
|
-
return int(self.value)
|
|
262
|
+
return value
|
|
256
263
|
|
|
257
264
|
def emit(self, param: Optional[AnonPositionalArg] = None) -> ArgValue:
|
|
258
265
|
from classiq.model_expansions.closure import FunctionClosure
|
|
@@ -11,9 +11,7 @@ from classiq.interface.model.native_function_definition import NativeFunctionDef
|
|
|
11
11
|
from classiq.interface.model.port_declaration import PortDeclaration
|
|
12
12
|
from classiq.interface.model.quantum_function_declaration import PositionalArg
|
|
13
13
|
|
|
14
|
-
from classiq.evaluators.classical_expression import
|
|
15
|
-
evaluate_classical_expression,
|
|
16
|
-
)
|
|
14
|
+
from classiq.evaluators.classical_expression import evaluate_classical_expression
|
|
17
15
|
from classiq.evaluators.parameter_types import (
|
|
18
16
|
evaluate_type_in_quantum_symbol,
|
|
19
17
|
)
|
|
@@ -33,9 +31,8 @@ from classiq.qmod.semantics.annotation.qstruct_annotator import QStructAnnotator
|
|
|
33
31
|
|
|
34
32
|
def add_constants_to_scope(constants: list[Constant], scope: Scope) -> None:
|
|
35
33
|
for constant in constants:
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
)
|
|
34
|
+
expr_val = evaluate_classical_expression(constant.value, scope).value
|
|
35
|
+
scope[constant.name] = Evaluated(value=expr_val)
|
|
39
36
|
|
|
40
37
|
|
|
41
38
|
def add_functions_to_scope(
|
|
@@ -16,11 +16,15 @@ from sympy.logic.boolalg import BooleanAtom
|
|
|
16
16
|
from sympy.printing.pycode import PythonCodePrinter
|
|
17
17
|
|
|
18
18
|
from classiq.interface.exceptions import ClassiqInternalExpansionError
|
|
19
|
-
from classiq.interface.generator.expressions.expression_types import
|
|
19
|
+
from classiq.interface.generator.expressions.expression_types import (
|
|
20
|
+
ExpressionValue,
|
|
21
|
+
RuntimeConstant,
|
|
22
|
+
)
|
|
20
23
|
from classiq.interface.generator.expressions.proxies.classical.any_classical_value import (
|
|
21
24
|
AnyClassicalValue,
|
|
22
25
|
)
|
|
23
26
|
|
|
27
|
+
from classiq.evaluators.qmod_annotated_expression import QmodAnnotatedExpression
|
|
24
28
|
from classiq.evaluators.qmod_expression_visitors.sympy_wrappers import LogicalXor
|
|
25
29
|
|
|
26
30
|
|
|
@@ -48,7 +52,7 @@ def sympy_to_python(
|
|
|
48
52
|
if value is None:
|
|
49
53
|
value = False
|
|
50
54
|
|
|
51
|
-
if not isinstance(value, get_args(
|
|
55
|
+
if not isinstance(value, (*get_args(RuntimeConstant), QmodAnnotatedExpression)):
|
|
52
56
|
raise ClassiqInternalExpansionError(
|
|
53
57
|
f"Invalid evaluated expression {value} of type {type(value)}"
|
|
54
58
|
)
|
|
@@ -1,26 +1,27 @@
|
|
|
1
|
-
import ast
|
|
2
1
|
import re
|
|
3
2
|
from collections.abc import Mapping, Sequence
|
|
4
3
|
from dataclasses import dataclass
|
|
5
|
-
from functools import cmp_to_key
|
|
6
4
|
from typing import TypeVar, cast
|
|
7
5
|
|
|
8
|
-
from classiq.interface.
|
|
6
|
+
from classiq.interface.generator.expressions.atomic_expression_functions import (
|
|
7
|
+
CLASSICAL_ATTRIBUTES,
|
|
8
|
+
)
|
|
9
9
|
from classiq.interface.generator.expressions.evaluated_expression import (
|
|
10
10
|
EvaluatedExpression,
|
|
11
11
|
)
|
|
12
12
|
from classiq.interface.generator.expressions.expression import Expression
|
|
13
|
-
from classiq.interface.generator.expressions.proxies.classical.any_classical_value import (
|
|
14
|
-
AnyClassicalValue,
|
|
15
|
-
)
|
|
16
13
|
from classiq.interface.generator.visitor import NodeType
|
|
17
|
-
from classiq.interface.model.handle_binding import HandleBinding
|
|
14
|
+
from classiq.interface.model.handle_binding import FieldHandleBinding, HandleBinding
|
|
18
15
|
from classiq.interface.model.model_visitor import ModelTransformer
|
|
19
16
|
from classiq.interface.model.quantum_expressions.quantum_expression import (
|
|
20
17
|
QuantumExpressionOperation,
|
|
21
18
|
)
|
|
22
19
|
|
|
23
|
-
from classiq.
|
|
20
|
+
from classiq.evaluators.qmod_annotated_expression import QmodAnnotatedExpression
|
|
21
|
+
from classiq.evaluators.qmod_expression_visitors.qmod_expression_renamer import (
|
|
22
|
+
replace_expression_type_attrs,
|
|
23
|
+
replace_expression_vars,
|
|
24
|
+
)
|
|
24
25
|
|
|
25
26
|
AST_NODE = TypeVar("AST_NODE", bound=NodeType)
|
|
26
27
|
|
|
@@ -39,31 +40,6 @@ def _handle_contains_handle(handle: HandleBinding, other_handle: HandleBinding)
|
|
|
39
40
|
return 0
|
|
40
41
|
|
|
41
42
|
|
|
42
|
-
class ExprNormalizer(ast.NodeTransformer):
|
|
43
|
-
def visit_Call(self, node: ast.Call) -> ast.AST:
|
|
44
|
-
if not isinstance(node.func, ast.Name):
|
|
45
|
-
return self.generic_visit(node)
|
|
46
|
-
if node.func.id == "get_field":
|
|
47
|
-
if (
|
|
48
|
-
len(node.args) != 2
|
|
49
|
-
or not isinstance(node.args[1], ast.Constant)
|
|
50
|
-
or not isinstance(node.args[1].value, str)
|
|
51
|
-
):
|
|
52
|
-
raise ClassiqInternalExpansionError("Unexpected 'get_field' arguments")
|
|
53
|
-
return ast.Attribute(
|
|
54
|
-
value=self.visit(node.args[0]), attr=node.args[1].value
|
|
55
|
-
)
|
|
56
|
-
if node.func.id == "do_subscript":
|
|
57
|
-
if len(node.args) != 2:
|
|
58
|
-
raise ClassiqInternalExpansionError(
|
|
59
|
-
"Unexpected 'do_subscript' arguments"
|
|
60
|
-
)
|
|
61
|
-
return ast.Subscript(
|
|
62
|
-
value=self.visit(node.args[0]), slice=self.visit(node.args[1])
|
|
63
|
-
)
|
|
64
|
-
return self.generic_visit(node)
|
|
65
|
-
|
|
66
|
-
|
|
67
43
|
@dataclass(frozen=True)
|
|
68
44
|
class HandleRenaming:
|
|
69
45
|
source_handle: HandleBinding
|
|
@@ -80,38 +56,33 @@ SymbolRenaming = Mapping[HandleBinding, Sequence[HandleRenaming]]
|
|
|
80
56
|
def rewrite_expression(
|
|
81
57
|
symbol_mapping: SymbolRenaming, expression: Expression
|
|
82
58
|
) -> Expression:
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
)
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
for
|
|
92
|
-
|
|
93
|
-
|
|
59
|
+
if len(symbol_mapping) == 0:
|
|
60
|
+
return expression
|
|
61
|
+
expr_val = expression.value.value
|
|
62
|
+
if not isinstance(expr_val, QmodAnnotatedExpression):
|
|
63
|
+
return expression
|
|
64
|
+
|
|
65
|
+
type_attr_mapping = {
|
|
66
|
+
(source_handle.base_handle, source_attr): renaming.target_var_handle
|
|
67
|
+
for renamings in symbol_mapping.values()
|
|
68
|
+
for renaming in renamings
|
|
69
|
+
if isinstance(source_handle := renaming.source_handle, FieldHandleBinding)
|
|
70
|
+
and (source_attr := source_handle.field) in CLASSICAL_ATTRIBUTES
|
|
94
71
|
}
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
new_expr = Expression(expr=new_expr_str)
|
|
110
|
-
if not new_expr.is_evaluated():
|
|
111
|
-
new_expr._evaluated_expr = EvaluatedExpression(
|
|
112
|
-
value=AnyClassicalValue(new_expr_str)
|
|
113
|
-
)
|
|
114
|
-
return new_expr
|
|
72
|
+
expr_val = replace_expression_type_attrs(expr_val, type_attr_mapping)
|
|
73
|
+
|
|
74
|
+
var_mapping = {
|
|
75
|
+
source_handle: renaming.target_var_handle
|
|
76
|
+
for renamings in symbol_mapping.values()
|
|
77
|
+
for renaming in renamings
|
|
78
|
+
if not isinstance(source_handle := renaming.source_handle, FieldHandleBinding)
|
|
79
|
+
or source_handle.field not in CLASSICAL_ATTRIBUTES
|
|
80
|
+
}
|
|
81
|
+
expr_val = replace_expression_vars(expr_val, var_mapping)
|
|
82
|
+
|
|
83
|
+
renamed_expr = Expression(expr=str(expr_val))
|
|
84
|
+
renamed_expr._evaluated_expr = EvaluatedExpression(value=expr_val)
|
|
85
|
+
return renamed_expr
|
|
115
86
|
|
|
116
87
|
|
|
117
88
|
class _ReplaceSplitVarsHandles(ModelTransformer):
|
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
import ast
|
|
2
1
|
import functools
|
|
3
2
|
import itertools
|
|
4
3
|
import warnings
|
|
@@ -37,7 +36,7 @@ from classiq.interface.model.quantum_function_call import QuantumFunctionCall
|
|
|
37
36
|
from classiq.interface.model.within_apply_operation import WithinApply
|
|
38
37
|
from classiq.interface.source_reference import SourceReference
|
|
39
38
|
|
|
40
|
-
from classiq.
|
|
39
|
+
from classiq.evaluators.qmod_annotated_expression import QmodAnnotatedExpression
|
|
41
40
|
|
|
42
41
|
|
|
43
42
|
def _inconsistent_type_modifier_error(
|
|
@@ -302,11 +301,12 @@ class TypeModifierValidation(ModelVisitor):
|
|
|
302
301
|
|
|
303
302
|
@staticmethod
|
|
304
303
|
def _extract_expr_vars(expr_op: QuantumExpressionOperation) -> list[str]:
|
|
305
|
-
|
|
306
|
-
|
|
304
|
+
expr_val = expr_op.expression.value.value
|
|
305
|
+
if not isinstance(expr_val, QmodAnnotatedExpression):
|
|
306
|
+
return []
|
|
307
|
+
return list(
|
|
308
|
+
dict.fromkeys(var.name for var in expr_val.get_quantum_vars().values())
|
|
307
309
|
)
|
|
308
|
-
vrc.visit(ast.parse(expr_op.expression.expr))
|
|
309
|
-
return [handle.name for handle in vrc.var_handles]
|
|
310
310
|
|
|
311
311
|
def visit_ArithmeticOperation(self, arith: ArithmeticOperation) -> None:
|
|
312
312
|
with self.source_reference_context(arith.source_ref):
|