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
|
@@ -3,7 +3,7 @@ from collections import UserDict
|
|
|
3
3
|
from collections.abc import Iterator
|
|
4
4
|
from dataclasses import dataclass
|
|
5
5
|
from functools import singledispatch
|
|
6
|
-
from typing import TYPE_CHECKING, Any,
|
|
6
|
+
from typing import TYPE_CHECKING, Any, Optional, TypeVar, Union
|
|
7
7
|
|
|
8
8
|
import sympy
|
|
9
9
|
|
|
@@ -15,15 +15,11 @@ 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
|
)
|
|
24
21
|
from classiq.interface.generator.functions.classical_type import ClassicalType
|
|
25
22
|
from classiq.interface.generator.functions.type_name import TypeName
|
|
26
|
-
from classiq.interface.helpers.text_utils import readable_list, s
|
|
27
23
|
from classiq.interface.model.handle_binding import (
|
|
28
24
|
FieldHandleBinding,
|
|
29
25
|
GeneralHandle,
|
|
@@ -43,6 +39,9 @@ from classiq.interface.model.quantum_type import (
|
|
|
43
39
|
QuantumType,
|
|
44
40
|
)
|
|
45
41
|
|
|
42
|
+
from classiq.evaluators.qmod_annotated_expression import QmodAnnotatedExpression
|
|
43
|
+
from classiq.evaluators.qmod_node_evaluators.utils import get_sympy_val
|
|
44
|
+
|
|
46
45
|
if TYPE_CHECKING:
|
|
47
46
|
from classiq.model_expansions.closure import FunctionClosure
|
|
48
47
|
|
|
@@ -69,7 +68,7 @@ class QuantumSymbol(QuantumVariable):
|
|
|
69
68
|
return self.handle
|
|
70
69
|
|
|
71
70
|
def __getitem__(
|
|
72
|
-
self, item: Union[slice, int,
|
|
71
|
+
self, item: Union[slice, int, QmodAnnotatedExpression]
|
|
73
72
|
) -> "QuantumSymbol":
|
|
74
73
|
if isinstance(item, slice):
|
|
75
74
|
return self._slice(item.start, item.stop)
|
|
@@ -77,8 +76,8 @@ class QuantumSymbol(QuantumVariable):
|
|
|
77
76
|
|
|
78
77
|
def _slice(
|
|
79
78
|
self,
|
|
80
|
-
start: Union[int,
|
|
81
|
-
end: Union[int,
|
|
79
|
+
start: Union[int, QmodAnnotatedExpression],
|
|
80
|
+
end: Union[int, QmodAnnotatedExpression],
|
|
82
81
|
) -> "QuantumSymbol":
|
|
83
82
|
if not isinstance(self.quantum_type, QuantumBitvector):
|
|
84
83
|
raise ClassiqExpansionError(
|
|
@@ -100,19 +99,27 @@ class QuantumSymbol(QuantumVariable):
|
|
|
100
99
|
f"{self.quantum_type.type_name.lower()} {str(self.handle)!r} (of "
|
|
101
100
|
f"length {self.quantum_type.length_value})"
|
|
102
101
|
)
|
|
102
|
+
start_expr = Expression(expr=str(start))
|
|
103
|
+
start_expr._evaluated_expr = EvaluatedExpression(value=start)
|
|
104
|
+
end_expr = Expression(expr=str(end))
|
|
105
|
+
end_expr._evaluated_expr = EvaluatedExpression(value=end)
|
|
106
|
+
if isinstance(start, int) and isinstance(end, int):
|
|
107
|
+
length_expr = Expression(expr=str(end - start))
|
|
108
|
+
else:
|
|
109
|
+
length_expr = None
|
|
103
110
|
return QuantumSymbol(
|
|
104
111
|
handle=SlicedHandleBinding(
|
|
105
112
|
base_handle=self.handle,
|
|
106
|
-
start=
|
|
107
|
-
end=
|
|
113
|
+
start=start_expr,
|
|
114
|
+
end=end_expr,
|
|
108
115
|
),
|
|
109
116
|
quantum_type=QuantumBitvector(
|
|
110
117
|
element_type=self.quantum_type.element_type,
|
|
111
|
-
length=
|
|
118
|
+
length=length_expr,
|
|
112
119
|
),
|
|
113
120
|
)
|
|
114
121
|
|
|
115
|
-
def _subscript(self, index: Union[int,
|
|
122
|
+
def _subscript(self, index: Union[int, QmodAnnotatedExpression]) -> "QuantumSymbol":
|
|
116
123
|
if not isinstance(self.quantum_type, QuantumBitvector):
|
|
117
124
|
raise ClassiqExpansionError(
|
|
118
125
|
f"{self.quantum_type.type_name} is not subscriptable"
|
|
@@ -135,11 +142,10 @@ class QuantumSymbol(QuantumVariable):
|
|
|
135
142
|
f"{self.quantum_type.type_name.lower()} {str(self.handle)!r}"
|
|
136
143
|
f"{length_suffix}"
|
|
137
144
|
)
|
|
145
|
+
index_expr = Expression(expr=str(index))
|
|
146
|
+
index_expr._evaluated_expr = EvaluatedExpression(value=index)
|
|
138
147
|
return QuantumSymbol(
|
|
139
|
-
handle=SubscriptHandleBinding(
|
|
140
|
-
base_handle=self.handle,
|
|
141
|
-
index=Expression(expr=str(index)),
|
|
142
|
-
),
|
|
148
|
+
handle=SubscriptHandleBinding(base_handle=self.handle, index=index_expr),
|
|
143
149
|
quantum_type=self.quantum_type.element_type,
|
|
144
150
|
)
|
|
145
151
|
|
|
@@ -204,11 +210,15 @@ class QuantumSymbolList(QuantumVariable):
|
|
|
204
210
|
|
|
205
211
|
|
|
206
212
|
@dataclass(frozen=True)
|
|
207
|
-
class
|
|
208
|
-
handle: HandleBinding
|
|
213
|
+
class ClassicalVariable:
|
|
209
214
|
classical_type: ClassicalType
|
|
210
215
|
|
|
211
216
|
|
|
217
|
+
@dataclass(frozen=True)
|
|
218
|
+
class ClassicalSymbol(ClassicalVariable):
|
|
219
|
+
handle: HandleBinding
|
|
220
|
+
|
|
221
|
+
|
|
212
222
|
@singledispatch
|
|
213
223
|
def evaluated_to_str(value: Any) -> str:
|
|
214
224
|
return str(value)
|
|
@@ -224,35 +234,23 @@ def _evaluated_to_str_struct_literal(value: QmodStructInstance) -> str:
|
|
|
224
234
|
return f"struct_literal({value.struct_declaration.name}, {', '.join(f'{k}={evaluated_to_str(v)}' for k, v in value.fields.items())})"
|
|
225
235
|
|
|
226
236
|
|
|
227
|
-
def _raise_type_error(val: Any, t: type, location_hint: Optional[str]) -> NoReturn:
|
|
228
|
-
if isinstance(val, sympy.Basic) and len(val.free_symbols) > 0:
|
|
229
|
-
symbolic_vars = sorted(map(str, val.free_symbols))
|
|
230
|
-
suffix = f" {location_hint}" if location_hint is not None else ""
|
|
231
|
-
raise ClassiqExpansionError(
|
|
232
|
-
f"Cannot use execution parameter{s(symbolic_vars)} {readable_list(symbolic_vars, quote=True)} in a compile-time context{suffix}"
|
|
233
|
-
)
|
|
234
|
-
raise ClassiqExpansionError(f"Invalid access to expression {val!r} as {t}")
|
|
235
|
-
|
|
236
|
-
|
|
237
237
|
@dataclass(frozen=True)
|
|
238
238
|
class Evaluated: # FIXME: Merge with EvaluatedExpression if possible
|
|
239
239
|
value: Any
|
|
240
240
|
defining_function: Optional["FunctionClosure"] = None
|
|
241
241
|
|
|
242
|
-
def as_type(self, t: type[T]
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
if
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
if not isinstance(self.value, (int, float)):
|
|
253
|
-
_raise_type_error(self.value, int, location_hint)
|
|
242
|
+
def as_type(self, t: type[T]) -> T:
|
|
243
|
+
value = self.value
|
|
244
|
+
if isinstance(value, sympy.Basic):
|
|
245
|
+
value = get_sympy_val(value)
|
|
246
|
+
if t is int and isinstance(value, float):
|
|
247
|
+
value = int(value)
|
|
248
|
+
if not isinstance(value, t):
|
|
249
|
+
raise ClassiqExpansionError(
|
|
250
|
+
f"Invalid access to expression {self.value!r} as {t}"
|
|
251
|
+
)
|
|
254
252
|
|
|
255
|
-
return
|
|
253
|
+
return value
|
|
256
254
|
|
|
257
255
|
def emit(self, param: Optional[AnonPositionalArg] = None) -> ArgValue:
|
|
258
256
|
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(
|
|
@@ -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):
|
|
@@ -7,6 +7,7 @@ from classiq.interface.model.quantum_expressions.quantum_expression import (
|
|
|
7
7
|
QuantumExpressionOperation,
|
|
8
8
|
)
|
|
9
9
|
|
|
10
|
+
from classiq.evaluators.qmod_annotated_expression import QmodAnnotatedExpression
|
|
10
11
|
from classiq.model_expansions.visitors.variable_references import VarRefCollector
|
|
11
12
|
|
|
12
13
|
|
|
@@ -18,6 +19,12 @@ class _HandlesCollector(Visitor):
|
|
|
18
19
|
self.handles.append(handle)
|
|
19
20
|
|
|
20
21
|
def visit_Expression(self, expression: Expression) -> None:
|
|
22
|
+
if expression.is_evaluated():
|
|
23
|
+
expr_val = expression.value.value
|
|
24
|
+
if isinstance(expr_val, QmodAnnotatedExpression):
|
|
25
|
+
self.handles.extend(expr_val.get_classical_vars().values())
|
|
26
|
+
self.handles.extend(expr_val.get_quantum_vars().values())
|
|
27
|
+
return
|
|
21
28
|
vrc = VarRefCollector(ignore_duplicated_handles=True, unevaluated=True)
|
|
22
29
|
vrc.visit(ast.parse(expression.expr))
|
|
23
30
|
self.handles.extend(vrc.var_handles)
|
|
@@ -1,11 +1,9 @@
|
|
|
1
1
|
import ast
|
|
2
2
|
import copy
|
|
3
|
-
from typing import TYPE_CHECKING
|
|
3
|
+
from typing import TYPE_CHECKING
|
|
4
4
|
|
|
5
5
|
from classiq.interface.exceptions import ClassiqInternalExpansionError
|
|
6
6
|
|
|
7
|
-
from classiq.evaluators.qmod_expression_visitors.sympy_wrappers import LogicalXor
|
|
8
|
-
|
|
9
7
|
|
|
10
8
|
class BooleanExpressionOptimizer(ast.NodeTransformer):
|
|
11
9
|
"""
|
|
@@ -36,13 +34,13 @@ class BooleanExpressionOptimizer(ast.NodeTransformer):
|
|
|
36
34
|
self._is_convertible = False
|
|
37
35
|
return node
|
|
38
36
|
|
|
39
|
-
def visit_BinOp(self, node: ast.BinOp) ->
|
|
37
|
+
def visit_BinOp(self, node: ast.BinOp) -> ast.AST:
|
|
40
38
|
self.generic_visit(node)
|
|
41
39
|
self._is_convertible = self._is_bool(node)
|
|
42
40
|
if not self._is_convertible:
|
|
43
41
|
return node
|
|
44
42
|
|
|
45
|
-
return self.
|
|
43
|
+
return self._convert_bin_op_to_bool_op(node)
|
|
46
44
|
|
|
47
45
|
def visit_UnaryOp(self, node: ast.UnaryOp) -> ast.AST:
|
|
48
46
|
self.generic_visit(node)
|
|
@@ -70,9 +68,7 @@ class BooleanExpressionOptimizer(ast.NodeTransformer):
|
|
|
70
68
|
return self._simplify_trivial_equality(node)
|
|
71
69
|
|
|
72
70
|
def visit_Call(self, node: ast.Call) -> ast.Call:
|
|
73
|
-
self._is_convertible =
|
|
74
|
-
isinstance(node.func, ast.Name) and node.func.id == LogicalXor.__name__
|
|
75
|
-
)
|
|
71
|
+
self._is_convertible = False
|
|
76
72
|
return node
|
|
77
73
|
|
|
78
74
|
def _is_bool(self, node: ast.AST) -> bool:
|
|
@@ -97,9 +93,7 @@ class BooleanExpressionOptimizer(ast.NodeTransformer):
|
|
|
97
93
|
and isinstance(node.ops[0], (ast.Eq, ast.NotEq))
|
|
98
94
|
)
|
|
99
95
|
if isinstance(node, ast.Call):
|
|
100
|
-
return
|
|
101
|
-
isinstance(node.func, ast.Name) and node.func.id == LogicalXor.__name__
|
|
102
|
-
)
|
|
96
|
+
return False
|
|
103
97
|
return False
|
|
104
98
|
|
|
105
99
|
def _convert_bin_op_to_bool_op(self, node: ast.BinOp) -> ast.AST:
|
|
@@ -116,11 +110,7 @@ class BooleanExpressionOptimizer(ast.NodeTransformer):
|
|
|
116
110
|
if not (
|
|
117
111
|
isinstance(node.left, ast.Constant) or isinstance(node.right, ast.Constant)
|
|
118
112
|
):
|
|
119
|
-
return ast.
|
|
120
|
-
func=ast.Name(LogicalXor.__name__),
|
|
121
|
-
args=[node.left, node.right],
|
|
122
|
-
keywords=[],
|
|
123
|
-
)
|
|
113
|
+
return ast.BinOp(left=node.left, op=ast.BitXor(), right=node.right)
|
|
124
114
|
|
|
125
115
|
if isinstance(node.left, ast.Constant):
|
|
126
116
|
constant = node.left.value
|
|
@@ -128,10 +118,7 @@ class BooleanExpressionOptimizer(ast.NodeTransformer):
|
|
|
128
118
|
else:
|
|
129
119
|
if TYPE_CHECKING:
|
|
130
120
|
assert isinstance(node.right, ast.Constant)
|
|
131
|
-
|
|
132
|
-
constant = node.right.value
|
|
133
|
-
except AttributeError as e:
|
|
134
|
-
raise e
|
|
121
|
+
constant = node.right.value
|
|
135
122
|
other = node.left
|
|
136
123
|
|
|
137
124
|
return other if constant == 0 else ast.UnaryOp(op=ast.Not(), operand=other)
|
|
@@ -201,14 +188,3 @@ class BooleanExpressionFuncLibAdapter(ast.NodeTransformer):
|
|
|
201
188
|
return node
|
|
202
189
|
self.generic_visit(node)
|
|
203
190
|
return ast.UnaryOp(op=ast.Not(), operand=node.operand)
|
|
204
|
-
|
|
205
|
-
def visit_BinOp(self, node: ast.BinOp) -> Union[ast.BinOp, ast.Call]:
|
|
206
|
-
"""Due to Sympy crap, we need to translate the Xor nodes to our LogicalXor"""
|
|
207
|
-
if not (self._is_boolean_optimized and isinstance(node.op, ast.BitXor)):
|
|
208
|
-
return node
|
|
209
|
-
self.generic_visit(node)
|
|
210
|
-
return ast.Call(
|
|
211
|
-
func=ast.Name(LogicalXor.__name__),
|
|
212
|
-
args=[node.left, node.right],
|
|
213
|
-
keywords=[],
|
|
214
|
-
)
|
|
@@ -100,6 +100,7 @@ class SymbolicParamInference(ModelVisitor):
|
|
|
100
100
|
)
|
|
101
101
|
self._inferred_funcs: set[str] = set()
|
|
102
102
|
self._scope: Mapping[str, ClassicalType] = {}
|
|
103
|
+
self._quantum_scope: set[str] = set()
|
|
103
104
|
self._scope_operands: dict[str, QuantumOperandDeclaration] = {}
|
|
104
105
|
|
|
105
106
|
def infer(self) -> None:
|
|
@@ -109,16 +110,19 @@ class SymbolicParamInference(ModelVisitor):
|
|
|
109
110
|
@contextmanager
|
|
110
111
|
def function_context(
|
|
111
112
|
self,
|
|
112
|
-
func_name: Optional[str],
|
|
113
113
|
scope: Mapping[str, ClassicalType],
|
|
114
|
+
quantum_scope: set[str],
|
|
114
115
|
scope_operands: dict[str, QuantumOperandDeclaration],
|
|
115
116
|
) -> Iterator[None]:
|
|
116
117
|
prev_scope = self._scope
|
|
117
118
|
self._scope = scope
|
|
119
|
+
prev_quantum_scope = self._quantum_scope
|
|
120
|
+
self._quantum_scope = quantum_scope
|
|
118
121
|
prev_scope_ops = self._scope_operands
|
|
119
122
|
self._scope_operands = scope_operands
|
|
120
123
|
yield
|
|
121
124
|
self._scope = prev_scope
|
|
125
|
+
self._quantum_scope = prev_quantum_scope
|
|
122
126
|
self._scope_operands = prev_scope_ops
|
|
123
127
|
|
|
124
128
|
def _infer_func_params(self, func: NativeFunctionDefinition) -> None:
|
|
@@ -126,8 +130,9 @@ class SymbolicParamInference(ModelVisitor):
|
|
|
126
130
|
return
|
|
127
131
|
self._inferred_funcs.add(func.name)
|
|
128
132
|
scope = {param.name: param.classical_type for param in func.param_decls}
|
|
133
|
+
quantum_scope = set(func.port_names)
|
|
129
134
|
scope_operands = func.operand_declarations_dict
|
|
130
|
-
with self.function_context(
|
|
135
|
+
with self.function_context(scope, quantum_scope, scope_operands):
|
|
131
136
|
for param in func.positional_arg_declarations:
|
|
132
137
|
for expr in _get_param_expressions(param):
|
|
133
138
|
self._process_compile_time_expression(expr.expr)
|
|
@@ -139,13 +144,14 @@ class SymbolicParamInference(ModelVisitor):
|
|
|
139
144
|
cast(str, param.name): param.classical_type
|
|
140
145
|
for param in func.named_func_decl.param_decls
|
|
141
146
|
}
|
|
147
|
+
quantum_scope = set(self._quantum_scope) | set(func.named_func_decl.port_names)
|
|
142
148
|
scope_operands = self._scope_operands | nameables_to_dict(
|
|
143
149
|
cast(
|
|
144
150
|
Sequence[QuantumOperandDeclaration],
|
|
145
151
|
func.named_func_decl.operand_declarations,
|
|
146
152
|
)
|
|
147
153
|
)
|
|
148
|
-
with self.function_context(
|
|
154
|
+
with self.function_context(scope, quantum_scope, scope_operands):
|
|
149
155
|
self.visit(func.body)
|
|
150
156
|
|
|
151
157
|
def visit_QuantumFunctionCall(self, call: QuantumFunctionCall) -> None:
|
|
@@ -327,7 +327,7 @@ def _classical_hadamard_transform(arr: list[float]) -> np.ndarray:
|
|
|
327
327
|
@qfunc
|
|
328
328
|
def apply_phase_table(
|
|
329
329
|
phases: list[float],
|
|
330
|
-
target: QArray[QBit, Literal["log(
|
|
330
|
+
target: QArray[QBit, Literal["log(phases.len, 2)"]],
|
|
331
331
|
) -> None:
|
|
332
332
|
alphas = -2 * _classical_hadamard_transform(phases) / np.sqrt(len(phases))
|
|
333
333
|
|
|
@@ -344,7 +344,7 @@ def apply_phase_table(
|
|
|
344
344
|
def inplace_prepare_complex_amplitudes(
|
|
345
345
|
magnitudes: CArray[CReal],
|
|
346
346
|
phases: list[float],
|
|
347
|
-
target: QArray[QBit, Literal["log(
|
|
347
|
+
target: QArray[QBit, Literal["log(magnitudes.len, 2)"]],
|
|
348
348
|
) -> None:
|
|
349
349
|
"""
|
|
350
350
|
|
|
@@ -367,7 +367,7 @@ def inplace_prepare_complex_amplitudes(
|
|
|
367
367
|
def prepare_complex_amplitudes(
|
|
368
368
|
magnitudes: CArray[CReal],
|
|
369
369
|
phases: list[float],
|
|
370
|
-
out: Output[QArray[QBit, Literal["log(
|
|
370
|
+
out: Output[QArray[QBit, Literal["log(magnitudes.len, 2)"]]],
|
|
371
371
|
) -> None:
|
|
372
372
|
"""
|
|
373
373
|
|
|
@@ -25,7 +25,7 @@ def free(in_: Permutable[Input[QArray[QBit]]]) -> None:
|
|
|
25
25
|
def prepare_state(
|
|
26
26
|
probabilities: CArray[CReal],
|
|
27
27
|
bound: CReal,
|
|
28
|
-
out: Output[QArray[QBit, Literal["log(
|
|
28
|
+
out: Output[QArray[QBit, Literal["log(probabilities.len, 2)"]]],
|
|
29
29
|
) -> None:
|
|
30
30
|
"""
|
|
31
31
|
[Qmod core-library function]
|
|
@@ -54,7 +54,7 @@ def prepare_state(
|
|
|
54
54
|
def prepare_amplitudes(
|
|
55
55
|
amplitudes: CArray[CReal],
|
|
56
56
|
bound: CReal,
|
|
57
|
-
out: Output[QArray[QBit, Literal["log(
|
|
57
|
+
out: Output[QArray[QBit, Literal["log(amplitudes.len, 2)"]]],
|
|
58
58
|
) -> None:
|
|
59
59
|
"""
|
|
60
60
|
[Qmod core-library function]
|
|
@@ -83,7 +83,7 @@ def prepare_amplitudes(
|
|
|
83
83
|
def inplace_prepare_state(
|
|
84
84
|
probabilities: CArray[CReal],
|
|
85
85
|
bound: CReal,
|
|
86
|
-
target: QArray[QBit, Literal["log(
|
|
86
|
+
target: QArray[QBit, Literal["log(probabilities.len, 2)"]],
|
|
87
87
|
) -> None:
|
|
88
88
|
"""
|
|
89
89
|
[Qmod core-library function]
|
|
@@ -106,7 +106,7 @@ def inplace_prepare_state(
|
|
|
106
106
|
def inplace_prepare_amplitudes(
|
|
107
107
|
amplitudes: CArray[CReal],
|
|
108
108
|
bound: CReal,
|
|
109
|
-
target: QArray[QBit, Literal["log(
|
|
109
|
+
target: QArray[QBit, Literal["log(amplitudes.len, 2)"]],
|
|
110
110
|
) -> None:
|
|
111
111
|
"""
|
|
112
112
|
[Qmod core-library function]
|
|
@@ -129,7 +129,7 @@ def inplace_prepare_amplitudes(
|
|
|
129
129
|
def inplace_prepare_amplitudes_approx(
|
|
130
130
|
amplitudes: CArray[CReal],
|
|
131
131
|
bound: CReal,
|
|
132
|
-
target: QArray[QBit, Literal["log(
|
|
132
|
+
target: QArray[QBit, Literal["log(amplitudes.len, 2)"]],
|
|
133
133
|
) -> None:
|
|
134
134
|
pass
|
|
135
135
|
|
|
@@ -138,7 +138,7 @@ def inplace_prepare_amplitudes_approx(
|
|
|
138
138
|
def prepare_amplitudes_approx(
|
|
139
139
|
amplitudes: CArray[CReal],
|
|
140
140
|
bound: CReal,
|
|
141
|
-
out: Output[QArray[QBit, Literal["log(
|
|
141
|
+
out: Output[QArray[QBit, Literal["log(amplitudes.len, 2)"]]],
|
|
142
142
|
) -> None:
|
|
143
143
|
pass
|
|
144
144
|
|
|
@@ -147,7 +147,7 @@ def prepare_amplitudes_approx(
|
|
|
147
147
|
def inplace_prepare_state_approx(
|
|
148
148
|
probabilities: CArray[CReal],
|
|
149
149
|
bound: CReal,
|
|
150
|
-
target: QArray[QBit, Literal["log(
|
|
150
|
+
target: QArray[QBit, Literal["log(probabilities.len, 2)"]],
|
|
151
151
|
) -> None:
|
|
152
152
|
pass
|
|
153
153
|
|
|
@@ -156,6 +156,6 @@ def inplace_prepare_state_approx(
|
|
|
156
156
|
def prepare_state_approx(
|
|
157
157
|
probabilities: CArray[CReal],
|
|
158
158
|
bound: CReal,
|
|
159
|
-
out: Output[QArray[QBit, Literal["log(
|
|
159
|
+
out: Output[QArray[QBit, Literal["log(probabilities.len, 2)"]]],
|
|
160
160
|
) -> None:
|
|
161
161
|
pass
|
|
@@ -16,7 +16,7 @@ from classiq.qmod.qmod_variable import (
|
|
|
16
16
|
@qfunc(external=True)
|
|
17
17
|
def unitary(
|
|
18
18
|
elements: CArray[CArray[CReal]],
|
|
19
|
-
target: QArray[QBit, Literal["log(
|
|
19
|
+
target: QArray[QBit, Literal["log(elements[0].len, 2)"]],
|
|
20
20
|
) -> None:
|
|
21
21
|
"""
|
|
22
22
|
[Qmod core-library function]
|