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,413 +0,0 @@
|
|
|
1
|
-
from collections.abc import Mapping
|
|
2
|
-
from enum import Enum
|
|
3
|
-
from typing import Any, Callable, Union, get_args
|
|
4
|
-
|
|
5
|
-
import sympy
|
|
6
|
-
from sympy import Eq, Expr, Piecewise, Symbol
|
|
7
|
-
|
|
8
|
-
from classiq.interface.exceptions import (
|
|
9
|
-
ClassiqExpansionError,
|
|
10
|
-
ClassiqInternalExpansionError,
|
|
11
|
-
)
|
|
12
|
-
from classiq.interface.generator.expressions.atomic_expression_functions import (
|
|
13
|
-
MEASUREMENT_FUNCTIONS,
|
|
14
|
-
)
|
|
15
|
-
from classiq.interface.generator.expressions.expression_types import (
|
|
16
|
-
ExpressionValue,
|
|
17
|
-
QmodStructInstance,
|
|
18
|
-
)
|
|
19
|
-
from classiq.interface.generator.expressions.proxies.classical.any_classical_value import (
|
|
20
|
-
AnyClassicalValue,
|
|
21
|
-
)
|
|
22
|
-
from classiq.interface.generator.expressions.proxies.classical.classical_array_proxy import (
|
|
23
|
-
ClassicalArrayProxy,
|
|
24
|
-
ClassicalSequenceProxy,
|
|
25
|
-
)
|
|
26
|
-
from classiq.interface.generator.expressions.proxies.classical.classical_proxy import (
|
|
27
|
-
ClassicalProxy,
|
|
28
|
-
)
|
|
29
|
-
from classiq.interface.generator.expressions.proxies.quantum.qmod_qscalar_proxy import (
|
|
30
|
-
QmodQNumProxy,
|
|
31
|
-
)
|
|
32
|
-
from classiq.interface.generator.expressions.proxies.quantum.qmod_qstruct_proxy import (
|
|
33
|
-
QmodQStructProxy,
|
|
34
|
-
)
|
|
35
|
-
from classiq.interface.generator.expressions.proxies.quantum.qmod_sized_proxy import (
|
|
36
|
-
QmodSizedProxy,
|
|
37
|
-
)
|
|
38
|
-
from classiq.interface.generator.expressions.type_proxy import TypeProxy
|
|
39
|
-
from classiq.interface.generator.functions.classical_function_declaration import (
|
|
40
|
-
ClassicalFunctionDeclaration,
|
|
41
|
-
)
|
|
42
|
-
from classiq.interface.generator.functions.classical_type import (
|
|
43
|
-
Bool,
|
|
44
|
-
ClassicalArray,
|
|
45
|
-
ClassicalTuple,
|
|
46
|
-
ClassicalType,
|
|
47
|
-
OpaqueHandle,
|
|
48
|
-
QmodPyObject,
|
|
49
|
-
Real,
|
|
50
|
-
StructMetaType,
|
|
51
|
-
)
|
|
52
|
-
from classiq.interface.generator.functions.type_name import TypeName
|
|
53
|
-
from classiq.interface.helpers.backward_compatibility import zip_strict
|
|
54
|
-
|
|
55
|
-
from classiq.evaluators.qmod_expression_visitors.sympy_wrappers import (
|
|
56
|
-
BitwiseAnd,
|
|
57
|
-
BitwiseNot,
|
|
58
|
-
BitwiseOr,
|
|
59
|
-
BitwiseXor,
|
|
60
|
-
LogicalXor,
|
|
61
|
-
LShift,
|
|
62
|
-
RShift,
|
|
63
|
-
)
|
|
64
|
-
from classiq.model_expansions.model_tables import (
|
|
65
|
-
HandleIdentifier,
|
|
66
|
-
HandleTable,
|
|
67
|
-
)
|
|
68
|
-
from classiq.model_expansions.sympy_conversion.expression_to_sympy import (
|
|
69
|
-
MISSING_SLICE_VALUE_PLACEHOLDER,
|
|
70
|
-
)
|
|
71
|
-
from classiq.model_expansions.sympy_conversion.sympy_to_python import (
|
|
72
|
-
sympy_to_python,
|
|
73
|
-
)
|
|
74
|
-
from classiq.model_expansions.utils.sympy_utils import is_constant_subscript
|
|
75
|
-
from classiq.qmod.builtins.classical_functions import (
|
|
76
|
-
__all__ as qmod_classical_functions,
|
|
77
|
-
)
|
|
78
|
-
from classiq.qmod.model_state_container import QMODULE
|
|
79
|
-
from classiq.qmod.utilities import qmod_val_to_expr_str
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
def qmod_val_to_python(val: ExpressionValue, qmod_type: ClassicalType) -> Any:
|
|
83
|
-
if isinstance(qmod_type, TypeName):
|
|
84
|
-
if (
|
|
85
|
-
isinstance(val, QmodStructInstance)
|
|
86
|
-
and val.struct_declaration == QMODULE.type_decls[qmod_type.name]
|
|
87
|
-
):
|
|
88
|
-
return {
|
|
89
|
-
field_name: qmod_val_to_python(val.fields[field_name], field_type)
|
|
90
|
-
for field_name, field_type in val.struct_declaration.variables.items()
|
|
91
|
-
}
|
|
92
|
-
|
|
93
|
-
if isinstance(val, (Enum, int)):
|
|
94
|
-
return val
|
|
95
|
-
|
|
96
|
-
elif isinstance(qmod_type, ClassicalArray):
|
|
97
|
-
if isinstance(val, list):
|
|
98
|
-
return [qmod_val_to_python(elem, qmod_type.element_type) for elem in val]
|
|
99
|
-
|
|
100
|
-
elif isinstance(qmod_type, ClassicalTuple):
|
|
101
|
-
if isinstance(val, list):
|
|
102
|
-
return [
|
|
103
|
-
qmod_val_to_python(elem, elem_type)
|
|
104
|
-
for elem_type, elem in zip_strict(
|
|
105
|
-
qmod_type.element_types, val, strict=True
|
|
106
|
-
)
|
|
107
|
-
]
|
|
108
|
-
|
|
109
|
-
elif isinstance(qmod_type, OpaqueHandle):
|
|
110
|
-
if isinstance(val, HandleIdentifier):
|
|
111
|
-
return HandleTable.get_handle_object(val)
|
|
112
|
-
|
|
113
|
-
elif isinstance(val, Expr):
|
|
114
|
-
return sympy_to_python(val)
|
|
115
|
-
|
|
116
|
-
elif isinstance(qmod_type, Real):
|
|
117
|
-
if isinstance(val, (float, int)):
|
|
118
|
-
return val
|
|
119
|
-
|
|
120
|
-
elif isinstance(qmod_type, Bool):
|
|
121
|
-
if isinstance(val, bool):
|
|
122
|
-
return val
|
|
123
|
-
|
|
124
|
-
elif isinstance(qmod_type, StructMetaType):
|
|
125
|
-
if isinstance(val, TypeProxy):
|
|
126
|
-
return val.struct_declaration
|
|
127
|
-
|
|
128
|
-
elif isinstance(val, int): # other scalars are represented as int
|
|
129
|
-
return val
|
|
130
|
-
|
|
131
|
-
raise ClassiqInternalExpansionError(
|
|
132
|
-
f"Bad value {val!r} of type {type(val)!r} for {qmod_type!r}"
|
|
133
|
-
)
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
def python_val_to_qmod(val: Any, qmod_type: ClassicalType) -> ExpressionValue:
|
|
137
|
-
if isinstance(qmod_type, TypeName):
|
|
138
|
-
if qmod_type.name in QMODULE.enum_decls:
|
|
139
|
-
return val
|
|
140
|
-
|
|
141
|
-
struct_decl = QMODULE.type_decls[qmod_type.name]
|
|
142
|
-
if not isinstance(val, Mapping):
|
|
143
|
-
raise ClassiqInternalExpansionError(
|
|
144
|
-
f"Bad value for struct {struct_decl.name}"
|
|
145
|
-
)
|
|
146
|
-
qmod_dict = {
|
|
147
|
-
field_name: python_val_to_qmod(val[field_name], field_type)
|
|
148
|
-
for field_name, field_type in struct_decl.variables.items()
|
|
149
|
-
}
|
|
150
|
-
return QmodStructInstance(struct_decl.model_copy(deep=True), qmod_dict)
|
|
151
|
-
|
|
152
|
-
if isinstance(qmod_type, ClassicalArray):
|
|
153
|
-
if not isinstance(val, list):
|
|
154
|
-
raise ClassiqInternalExpansionError("Bad value for list")
|
|
155
|
-
return [python_val_to_qmod(elem, qmod_type.element_type) for elem in val]
|
|
156
|
-
|
|
157
|
-
if isinstance(qmod_type, ClassicalTuple):
|
|
158
|
-
if not isinstance(val, list):
|
|
159
|
-
raise ClassiqInternalExpansionError("Bad value for list")
|
|
160
|
-
return [
|
|
161
|
-
python_val_to_qmod(elem, elem_type)
|
|
162
|
-
for elem, elem_type in zip_strict(val, qmod_type.element_types, strict=True)
|
|
163
|
-
]
|
|
164
|
-
|
|
165
|
-
if isinstance(qmod_type, OpaqueHandle):
|
|
166
|
-
if not isinstance(val, QmodPyObject):
|
|
167
|
-
raise ClassiqInternalExpansionError("Bad value opaque handle")
|
|
168
|
-
return HandleTable.set_handle_object(val)
|
|
169
|
-
|
|
170
|
-
return val
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
def python_call_wrapper(func: Callable, *args: ExpressionValue) -> Any:
|
|
174
|
-
func_decl = ClassicalFunctionDeclaration.FOREIGN_FUNCTION_DECLARATIONS[
|
|
175
|
-
func.__name__
|
|
176
|
-
]
|
|
177
|
-
python_args = [
|
|
178
|
-
qmod_val_to_python(args[idx], param_type.classical_type)
|
|
179
|
-
for idx, param_type in enumerate(func_decl.param_decls)
|
|
180
|
-
]
|
|
181
|
-
assert func_decl.return_type is not None
|
|
182
|
-
return python_val_to_qmod(func(*python_args), func_decl.return_type)
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
def struct_literal(struct_type_symbol: Symbol, **kwargs: Any) -> QmodStructInstance:
|
|
186
|
-
return QmodStructInstance(
|
|
187
|
-
QMODULE.type_decls[struct_type_symbol.name].model_copy(deep=True),
|
|
188
|
-
{field: sympy_to_python(field_value) for field, field_value in kwargs.items()},
|
|
189
|
-
)
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
def get_field(
|
|
193
|
-
proxy: Union[
|
|
194
|
-
QmodSizedProxy, QmodStructInstance, list, ClassicalProxy, AnyClassicalValue
|
|
195
|
-
],
|
|
196
|
-
field: str,
|
|
197
|
-
) -> ExpressionValue:
|
|
198
|
-
if isinstance(proxy, AnyClassicalValue) or (
|
|
199
|
-
isinstance(proxy, Symbol)
|
|
200
|
-
and not isinstance(proxy, QmodSizedProxy)
|
|
201
|
-
and not isinstance(proxy, ClassicalProxy)
|
|
202
|
-
):
|
|
203
|
-
return AnyClassicalValue(f"get_field({qmod_val_to_expr_str(proxy)}, '{field}')")
|
|
204
|
-
if isinstance(proxy, type) and issubclass(proxy, Enum):
|
|
205
|
-
return getattr(proxy, field)
|
|
206
|
-
if isinstance(proxy, list):
|
|
207
|
-
if field != "len":
|
|
208
|
-
raise ClassiqExpansionError(
|
|
209
|
-
f"List {str(proxy)!r} has no attribute {field!r}. "
|
|
210
|
-
f"Available attributes: len"
|
|
211
|
-
)
|
|
212
|
-
return len(proxy)
|
|
213
|
-
if not isinstance(
|
|
214
|
-
proxy, (QmodSizedProxy, QmodStructInstance, ClassicalProxy, AnyClassicalValue)
|
|
215
|
-
):
|
|
216
|
-
raise ClassiqExpansionError(
|
|
217
|
-
f"Object {str(proxy)!r} has not attribute {field!r}"
|
|
218
|
-
)
|
|
219
|
-
if field not in proxy.fields:
|
|
220
|
-
if isinstance(proxy, (QmodStructInstance, QmodQStructProxy)):
|
|
221
|
-
property_name = "field"
|
|
222
|
-
else:
|
|
223
|
-
property_name = "attribute"
|
|
224
|
-
suffix = (
|
|
225
|
-
f". Available {property_name}s: {', '.join(proxy.fields.keys())}"
|
|
226
|
-
if len(proxy.fields) > 0
|
|
227
|
-
else ""
|
|
228
|
-
)
|
|
229
|
-
proxy_str = proxy.__name__ if isinstance(proxy, type) else f"{str(proxy)!r}"
|
|
230
|
-
raise ClassiqExpansionError(
|
|
231
|
-
f"{proxy.type_name} {proxy_str} has no {property_name} {field!r}{suffix}"
|
|
232
|
-
)
|
|
233
|
-
return proxy.fields[field]
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
def get_type(struct_type: Symbol) -> TypeProxy:
|
|
237
|
-
return TypeProxy(QMODULE.type_decls[struct_type.name])
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
def do_div(lhs: Any, rhs: Any) -> Any:
|
|
241
|
-
res = lhs / rhs
|
|
242
|
-
if isinstance(res, sympy.Expr):
|
|
243
|
-
res = res.evalf()
|
|
244
|
-
return res
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
_EXPRESSION_TYPES = get_args(ExpressionValue)
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
def _is_qmod_value(val: Any) -> bool:
|
|
251
|
-
if not isinstance(val, slice):
|
|
252
|
-
return isinstance(val, _EXPRESSION_TYPES)
|
|
253
|
-
if val.start is not None and not isinstance(val.start, _EXPRESSION_TYPES):
|
|
254
|
-
return False
|
|
255
|
-
if val.stop is not None and not isinstance(val.stop, _EXPRESSION_TYPES):
|
|
256
|
-
return False
|
|
257
|
-
return val.step is None or isinstance(val.step, _EXPRESSION_TYPES)
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
def do_subscript(value: Any, index: Any) -> Any:
|
|
261
|
-
if not isinstance(value, (list, ClassicalSequenceProxy)) or not isinstance(
|
|
262
|
-
index, QmodQNumProxy
|
|
263
|
-
):
|
|
264
|
-
if isinstance(index, (QmodSizedProxy, QmodStructInstance)):
|
|
265
|
-
raise ClassiqExpansionError(
|
|
266
|
-
f"Subscript {value}[{index}] is not supported. Supported subscripts "
|
|
267
|
-
f"include:\n"
|
|
268
|
-
f"\t1. `qbv[idx]`, where `qbv` is a quantum array and `idx` is a "
|
|
269
|
-
f"classical integer.\n"
|
|
270
|
-
f"\t2. `l[n]`, where `l` is a list of classical real numbers and `n` "
|
|
271
|
-
f"is a classical or quantum integer."
|
|
272
|
-
)
|
|
273
|
-
if (
|
|
274
|
-
isinstance(value, list)
|
|
275
|
-
and not is_constant_subscript(index)
|
|
276
|
-
and _is_qmod_value(index)
|
|
277
|
-
):
|
|
278
|
-
return AnyClassicalValue(qmod_val_to_expr_str(value))[index]
|
|
279
|
-
return value[index]
|
|
280
|
-
if index.is_signed or index.fraction_digits > 0:
|
|
281
|
-
raise ClassiqExpansionError(
|
|
282
|
-
"Quantum numeric subscript must be an unsigned integer (is_signed=False, "
|
|
283
|
-
"fraction_digits=0)"
|
|
284
|
-
)
|
|
285
|
-
if isinstance(value, ClassicalSequenceProxy):
|
|
286
|
-
length = value.length
|
|
287
|
-
else:
|
|
288
|
-
length = len(value)
|
|
289
|
-
if not isinstance(length, sympy.Basic) and length != 2**index.size:
|
|
290
|
-
raise ClassiqExpansionError(
|
|
291
|
-
f"Quantum numeric subscript size mismatch: The quantum numeric has "
|
|
292
|
-
f"{index.size} qubits but the list size is {length} != 2**{index.size}"
|
|
293
|
-
)
|
|
294
|
-
if isinstance(value, ClassicalSequenceProxy):
|
|
295
|
-
return AnyClassicalValue(
|
|
296
|
-
f"do_subscript({qmod_val_to_expr_str(value)}, {qmod_val_to_expr_str(index)})"
|
|
297
|
-
)
|
|
298
|
-
else:
|
|
299
|
-
return Piecewise(
|
|
300
|
-
*[(item, Eq(index, idx)) for idx, item in enumerate(value[:-1])],
|
|
301
|
-
(value[-1], True),
|
|
302
|
-
)
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
def do_slice(value: Any, lower: Any, upper: Any) -> Any:
|
|
306
|
-
if isinstance(lower, Symbol) and str(lower) == MISSING_SLICE_VALUE_PLACEHOLDER:
|
|
307
|
-
lower = None
|
|
308
|
-
if isinstance(upper, Symbol) and str(upper) == MISSING_SLICE_VALUE_PLACEHOLDER:
|
|
309
|
-
upper = None
|
|
310
|
-
return do_subscript(value, slice(lower, upper))
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
def do_sum(val: Any) -> Any:
|
|
314
|
-
if (isinstance(val, sympy.Basic) and len(val.free_symbols) > 0) or (
|
|
315
|
-
isinstance(val, ClassicalArrayProxy) and not isinstance(val.length, int)
|
|
316
|
-
):
|
|
317
|
-
return AnyClassicalValue(f"sum({val})")
|
|
318
|
-
return sum(val)
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
do_sum.__name__ = "sum"
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
def mod_inverse(a: Any, b: Any) -> Any:
|
|
325
|
-
if (
|
|
326
|
-
isinstance(a, AnyClassicalValue)
|
|
327
|
-
or (isinstance(a, sympy.Basic) and len(a.free_symbols) > 0)
|
|
328
|
-
or isinstance(b, AnyClassicalValue)
|
|
329
|
-
or (isinstance(b, sympy.Basic) and len(b.free_symbols) > 0)
|
|
330
|
-
):
|
|
331
|
-
return AnyClassicalValue(f"mod_inverse({a}, {b})")
|
|
332
|
-
return sympy.mod_inverse(a, b)
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
def min_wrapper(*vals: Any) -> Any:
|
|
336
|
-
try:
|
|
337
|
-
return sympy.Min(*vals)
|
|
338
|
-
except ValueError:
|
|
339
|
-
return AnyClassicalValue(f"Min({', '.join(map(str, vals))})")
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
min_wrapper.__name__ = "min"
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
def Min_wrapper(*vals: Any) -> Any: # noqa: N802
|
|
346
|
-
return min_wrapper(*vals)
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
Min_wrapper.__name__ = "Min"
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
def max_wrapper(*vals: Any) -> Any:
|
|
353
|
-
try:
|
|
354
|
-
return sympy.Max(*vals)
|
|
355
|
-
except ValueError:
|
|
356
|
-
return AnyClassicalValue(f"Max({', '.join(map(str, vals))})")
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
max_wrapper.__name__ = "max"
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
def Max_wrapper(*vals: Any) -> Any: # noqa: N802
|
|
363
|
-
return max_wrapper(*vals)
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
Max_wrapper.__name__ = "Max"
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
CORE_LIB_FUNCTIONS_LIST: list[Callable] = [
|
|
370
|
-
print,
|
|
371
|
-
do_sum,
|
|
372
|
-
struct_literal,
|
|
373
|
-
get_field,
|
|
374
|
-
get_type,
|
|
375
|
-
do_div,
|
|
376
|
-
do_slice,
|
|
377
|
-
do_subscript,
|
|
378
|
-
BitwiseAnd,
|
|
379
|
-
BitwiseXor,
|
|
380
|
-
BitwiseNot,
|
|
381
|
-
BitwiseOr,
|
|
382
|
-
LogicalXor,
|
|
383
|
-
RShift,
|
|
384
|
-
LShift,
|
|
385
|
-
mod_inverse,
|
|
386
|
-
min_wrapper,
|
|
387
|
-
Min_wrapper,
|
|
388
|
-
max_wrapper,
|
|
389
|
-
Max_wrapper,
|
|
390
|
-
]
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
def _symbolic_function(func: str) -> Callable:
|
|
394
|
-
def wrapper(*args: Any) -> AnyClassicalValue:
|
|
395
|
-
return AnyClassicalValue(
|
|
396
|
-
f"{func}({', '.join(map(qmod_val_to_expr_str, args))})"
|
|
397
|
-
)
|
|
398
|
-
|
|
399
|
-
wrapper.__name__ = func
|
|
400
|
-
return wrapper
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
QMOD_CLASSICAL_FUNCTIONS = [
|
|
404
|
-
_symbolic_function(func)
|
|
405
|
-
for func in qmod_classical_functions + list(MEASUREMENT_FUNCTIONS)
|
|
406
|
-
]
|
|
407
|
-
|
|
408
|
-
ATOMIC_EXPRESSION_FUNCTIONS = {
|
|
409
|
-
**{
|
|
410
|
-
core_func.__name__: core_func
|
|
411
|
-
for core_func in CORE_LIB_FUNCTIONS_LIST + QMOD_CLASSICAL_FUNCTIONS
|
|
412
|
-
},
|
|
413
|
-
}
|
|
@@ -1,18 +0,0 @@
|
|
|
1
|
-
from typing import Optional
|
|
2
|
-
|
|
3
|
-
from classiq.interface.generator.expressions.handle_identifier import HandleIdentifier
|
|
4
|
-
from classiq.interface.generator.functions.classical_type import QmodPyObject
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
class HandleTable:
|
|
8
|
-
_handle_map: dict[HandleIdentifier, QmodPyObject] = {}
|
|
9
|
-
|
|
10
|
-
@classmethod
|
|
11
|
-
def get_handle_object(cls, hid: HandleIdentifier) -> Optional[QmodPyObject]:
|
|
12
|
-
return cls._handle_map.get(hid)
|
|
13
|
-
|
|
14
|
-
@classmethod
|
|
15
|
-
def set_handle_object(cls, qmod_object: QmodPyObject) -> HandleIdentifier:
|
|
16
|
-
hid = HandleIdentifier(id(qmod_object))
|
|
17
|
-
cls._handle_map[hid] = qmod_object
|
|
18
|
-
return hid
|
|
File without changes
|
|
@@ -1,181 +0,0 @@
|
|
|
1
|
-
import ast
|
|
2
|
-
from typing import TYPE_CHECKING, cast
|
|
3
|
-
|
|
4
|
-
from classiq.interface.exceptions import ClassiqExpansionError
|
|
5
|
-
|
|
6
|
-
MISSING_SLICE_VALUE_PLACEHOLDER = "MISSING_SLICE_VALUE"
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
def translate_to_sympy(expr: str) -> str:
|
|
10
|
-
node = ast.parse(expr)
|
|
11
|
-
node = ExpressionSympyTranslator().visit(node)
|
|
12
|
-
# node is a Module, we want an Expression
|
|
13
|
-
if TYPE_CHECKING:
|
|
14
|
-
assert isinstance(node.body[0], ast.Expr)
|
|
15
|
-
expression = ast.Expression(node.body[0].value)
|
|
16
|
-
|
|
17
|
-
return ast.unparse(ast.fix_missing_locations(expression))
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
class ExpressionSympyTranslator(ast.NodeTransformer):
|
|
21
|
-
BINARY_OPERATORS: dict[type[ast.AST], str] = {
|
|
22
|
-
ast.BitOr: "BitwiseOr",
|
|
23
|
-
ast.BitAnd: "BitwiseAnd",
|
|
24
|
-
ast.BitXor: "BitwiseXor",
|
|
25
|
-
ast.Div: "do_div",
|
|
26
|
-
ast.RShift: "RShift",
|
|
27
|
-
ast.LShift: "LShift",
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
UNARY_OPERATORS: dict[type[ast.AST], str] = {
|
|
31
|
-
ast.Invert: "BitwiseNot",
|
|
32
|
-
ast.Not: "Not",
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
BOOLEAN_OPERATORS: dict[type[ast.AST], str] = {
|
|
36
|
-
ast.Or: "Or",
|
|
37
|
-
ast.And: "And",
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
COMPARE_OPERATORS: dict[type[ast.AST], str] = {
|
|
41
|
-
ast.Eq: "Eq",
|
|
42
|
-
ast.NotEq: "Ne",
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
SPECIAL_FUNCTIONS: dict[str, str] = {
|
|
46
|
-
"max": "Max",
|
|
47
|
-
"min": "Min",
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
def visit_BinOp(self, node: ast.BinOp) -> ast.AST:
|
|
51
|
-
sympy_class = self.BINARY_OPERATORS.get(node.op.__class__)
|
|
52
|
-
if sympy_class is not None:
|
|
53
|
-
left = self.visit(node.left)
|
|
54
|
-
right = self.visit(node.right)
|
|
55
|
-
|
|
56
|
-
new_node = ast.Call(
|
|
57
|
-
func=ast.Name(id=sympy_class, ctx=ast.Load()),
|
|
58
|
-
args=[left, right],
|
|
59
|
-
starargs=None,
|
|
60
|
-
keywords=[],
|
|
61
|
-
kwargs=None,
|
|
62
|
-
)
|
|
63
|
-
|
|
64
|
-
return new_node
|
|
65
|
-
return self.generic_visit(node)
|
|
66
|
-
|
|
67
|
-
def visit_Compare(self, node: ast.Compare) -> ast.AST:
|
|
68
|
-
if len(node.ops) > 1:
|
|
69
|
-
raise ClassiqExpansionError(
|
|
70
|
-
f"Qmod expressions do not support chained comparison, as done in {ast.unparse(node)}"
|
|
71
|
-
)
|
|
72
|
-
sympy_class = self.COMPARE_OPERATORS.get(node.ops[0].__class__)
|
|
73
|
-
if sympy_class is not None:
|
|
74
|
-
left = self.visit(node.left)
|
|
75
|
-
right = self.visit(node.comparators[0])
|
|
76
|
-
|
|
77
|
-
new_node = ast.Call(
|
|
78
|
-
func=ast.Name(id=sympy_class, ctx=ast.Load()),
|
|
79
|
-
args=[left, right],
|
|
80
|
-
starargs=None,
|
|
81
|
-
keywords=[],
|
|
82
|
-
kwargs=None,
|
|
83
|
-
)
|
|
84
|
-
|
|
85
|
-
return new_node
|
|
86
|
-
return self.generic_visit(node)
|
|
87
|
-
|
|
88
|
-
def visit_BoolOp(self, node: ast.BoolOp) -> ast.AST:
|
|
89
|
-
sympy_class = self.BOOLEAN_OPERATORS.get(node.op.__class__)
|
|
90
|
-
if sympy_class is not None:
|
|
91
|
-
values = [self.visit(value) for value in node.values]
|
|
92
|
-
|
|
93
|
-
new_node = ast.Call(
|
|
94
|
-
func=ast.Name(id=sympy_class, ctx=ast.Load()),
|
|
95
|
-
args=values,
|
|
96
|
-
starargs=None,
|
|
97
|
-
keywords=[],
|
|
98
|
-
kwargs=None,
|
|
99
|
-
)
|
|
100
|
-
|
|
101
|
-
return new_node
|
|
102
|
-
return self.generic_visit(node)
|
|
103
|
-
|
|
104
|
-
def visit_UnaryOp(self, node: ast.UnaryOp) -> ast.AST:
|
|
105
|
-
sympy_class = self.UNARY_OPERATORS.get(node.op.__class__)
|
|
106
|
-
if sympy_class is not None:
|
|
107
|
-
operand = self.visit(node.operand)
|
|
108
|
-
|
|
109
|
-
new_node = ast.Call(
|
|
110
|
-
func=ast.Name(id=sympy_class, ctx=ast.Load()),
|
|
111
|
-
args=[operand],
|
|
112
|
-
starargs=None,
|
|
113
|
-
keywords=[],
|
|
114
|
-
kwargs=None,
|
|
115
|
-
)
|
|
116
|
-
|
|
117
|
-
return new_node
|
|
118
|
-
return self.generic_visit(node)
|
|
119
|
-
|
|
120
|
-
def visit_Call(self, node: ast.Call) -> ast.AST:
|
|
121
|
-
if isinstance(node.func, ast.Name) and node.func.id == "Piecewise":
|
|
122
|
-
return self._visit_piecewise(node)
|
|
123
|
-
|
|
124
|
-
if (
|
|
125
|
-
not isinstance(node.func, ast.Name)
|
|
126
|
-
or node.func.id not in self.SPECIAL_FUNCTIONS
|
|
127
|
-
):
|
|
128
|
-
return self.generic_visit(node)
|
|
129
|
-
|
|
130
|
-
return ast.Call(
|
|
131
|
-
func=ast.Name(self.SPECIAL_FUNCTIONS[node.func.id]),
|
|
132
|
-
args=[self.visit(arg) for arg in (node.args)],
|
|
133
|
-
keywords=[self.visit(arg) for arg in node.keywords],
|
|
134
|
-
)
|
|
135
|
-
|
|
136
|
-
def _visit_piecewise(self, node: ast.Call) -> ast.AST:
|
|
137
|
-
# sympy Piecewise expression may include bitwise operations:
|
|
138
|
-
# Piecewise((0, Eq(x, 0)), (0.5, Eq(x, 1) | Eq(x, 2)), (1, True))
|
|
139
|
-
# ^
|
|
140
|
-
# We should avoid converting these to 'BitwiseOr' and such.
|
|
141
|
-
return ast.Call(
|
|
142
|
-
func=node.func,
|
|
143
|
-
args=[
|
|
144
|
-
ast.Tuple(
|
|
145
|
-
elts=(
|
|
146
|
-
self.generic_visit(cast(ast.Tuple, arg).elts[0]),
|
|
147
|
-
cast(ast.Tuple, arg).elts[1],
|
|
148
|
-
)
|
|
149
|
-
)
|
|
150
|
-
for arg in node.args
|
|
151
|
-
],
|
|
152
|
-
keywords=node.keywords,
|
|
153
|
-
)
|
|
154
|
-
|
|
155
|
-
def visit_Subscript(self, node: ast.Subscript) -> ast.AST:
|
|
156
|
-
if isinstance(node.slice, ast.Slice):
|
|
157
|
-
if node.slice.lower is not None:
|
|
158
|
-
lower = self.visit(node.slice.lower)
|
|
159
|
-
else:
|
|
160
|
-
lower = ast.Name(MISSING_SLICE_VALUE_PLACEHOLDER)
|
|
161
|
-
if node.slice.upper is not None:
|
|
162
|
-
upper = self.visit(node.slice.upper)
|
|
163
|
-
else:
|
|
164
|
-
upper = ast.Name(MISSING_SLICE_VALUE_PLACEHOLDER)
|
|
165
|
-
return ast.Call(
|
|
166
|
-
func=ast.Name("do_slice"),
|
|
167
|
-
args=[self.visit(node.value), lower, upper],
|
|
168
|
-
keywords=[],
|
|
169
|
-
)
|
|
170
|
-
return ast.Call(
|
|
171
|
-
func=ast.Name("do_subscript"),
|
|
172
|
-
args=[self.visit(node.value), self.visit(node.slice)],
|
|
173
|
-
keywords=[],
|
|
174
|
-
)
|
|
175
|
-
|
|
176
|
-
def visit_Attribute(self, node: ast.Attribute) -> ast.Call:
|
|
177
|
-
return ast.Call(
|
|
178
|
-
func=ast.Name("get_field"),
|
|
179
|
-
args=[self.visit(node.value), ast.Constant(value=node.attr)],
|
|
180
|
-
keywords=[],
|
|
181
|
-
)
|