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
|
@@ -4,7 +4,7 @@ from collections import defaultdict
|
|
|
4
4
|
from collections.abc import Sequence
|
|
5
5
|
from contextlib import nullcontext
|
|
6
6
|
from functools import singledispatchmethod
|
|
7
|
-
from typing import Any, cast
|
|
7
|
+
from typing import Any, Callable, cast
|
|
8
8
|
|
|
9
9
|
from pydantic import ValidationError
|
|
10
10
|
|
|
@@ -16,10 +16,8 @@ from classiq.interface.exceptions import (
|
|
|
16
16
|
ClassiqExpansionError,
|
|
17
17
|
ClassiqInternalExpansionError,
|
|
18
18
|
)
|
|
19
|
-
from classiq.interface.generator.expressions.atomic_expression_functions import (
|
|
20
|
-
CLASSICAL_ATTRIBUTES,
|
|
21
|
-
)
|
|
22
19
|
from classiq.interface.generator.expressions.expression import Expression
|
|
20
|
+
from classiq.interface.generator.expressions.expression_types import ExpressionValue
|
|
23
21
|
from classiq.interface.generator.functions.classical_function_declaration import (
|
|
24
22
|
ClassicalFunctionDeclaration,
|
|
25
23
|
)
|
|
@@ -42,8 +40,20 @@ from classiq.interface.model.quantum_lambda_function import (
|
|
|
42
40
|
)
|
|
43
41
|
from classiq.interface.model.quantum_statement import QuantumStatement
|
|
44
42
|
|
|
45
|
-
from classiq.evaluators.classical_expression import
|
|
46
|
-
|
|
43
|
+
from classiq.evaluators.classical_expression import process_scope_val
|
|
44
|
+
from classiq.evaluators.qmod_annotated_expression import QmodAnnotatedExpression
|
|
45
|
+
from classiq.evaluators.qmod_expression_visitors.qmod_expression_bwc import (
|
|
46
|
+
QmodExpressionBwc,
|
|
47
|
+
)
|
|
48
|
+
from classiq.evaluators.qmod_expression_visitors.qmod_expression_evaluator import (
|
|
49
|
+
evaluate_qmod_expression,
|
|
50
|
+
)
|
|
51
|
+
from classiq.evaluators.qmod_expression_visitors.qmod_expression_simplifier import (
|
|
52
|
+
simplify_qmod_expression,
|
|
53
|
+
)
|
|
54
|
+
from classiq.evaluators.qmod_node_evaluators.utils import is_classical_integer
|
|
55
|
+
from classiq.evaluators.qmod_type_inference.classical_type_inference import (
|
|
56
|
+
infer_classical_type,
|
|
47
57
|
)
|
|
48
58
|
from classiq.model_expansions.closure import (
|
|
49
59
|
Closure,
|
|
@@ -67,7 +77,6 @@ from classiq.model_expansions.scope_initialization import (
|
|
|
67
77
|
init_top_level_scope,
|
|
68
78
|
)
|
|
69
79
|
from classiq.model_expansions.utils.counted_name_allocator import CountedNameAllocator
|
|
70
|
-
from classiq.model_expansions.visitors.variable_references import VarRefCollector
|
|
71
80
|
from classiq.qmod.builtins.constants import __all__ as builtin_constants
|
|
72
81
|
from classiq.qmod.builtins.enums import BUILTIN_ENUM_DECLARATIONS
|
|
73
82
|
from classiq.qmod.builtins.structs import BUILTIN_STRUCT_DECLARATIONS
|
|
@@ -75,7 +84,17 @@ from classiq.qmod.model_state_container import QMODULE
|
|
|
75
84
|
from classiq.qmod.semantics.annotation.qstruct_annotator import QStructAnnotator
|
|
76
85
|
from classiq.qmod.semantics.error_manager import ErrorManager
|
|
77
86
|
from classiq.qmod.semantics.validation.model_validation import validate_model
|
|
78
|
-
|
|
87
|
+
|
|
88
|
+
|
|
89
|
+
def _validate_index(val: ExpressionValue, subject: str) -> None:
|
|
90
|
+
if isinstance(val, QmodAnnotatedExpression):
|
|
91
|
+
val_type = val.get_type(val.root)
|
|
92
|
+
else:
|
|
93
|
+
val_type = infer_classical_type(val)
|
|
94
|
+
if not is_classical_integer(val_type):
|
|
95
|
+
raise ClassiqExpansionError(
|
|
96
|
+
f"{subject} indices must be integers, not {val_type.raw_qmod_type_name}"
|
|
97
|
+
)
|
|
79
98
|
|
|
80
99
|
|
|
81
100
|
class BaseInterpreter:
|
|
@@ -130,6 +149,12 @@ class BaseInterpreter:
|
|
|
130
149
|
try:
|
|
131
150
|
with self._error_manager.call("main"):
|
|
132
151
|
self._expand_main_func()
|
|
152
|
+
except RecursionError:
|
|
153
|
+
self._error_manager.add_error(
|
|
154
|
+
"RecursionError: maximum recursion depth exceeded. Tip: If your "
|
|
155
|
+
"program contains recursive functions, check for base cases using a "
|
|
156
|
+
"Python if-statement (instead of Qmod's `if_`)"
|
|
157
|
+
)
|
|
133
158
|
except Exception as e:
|
|
134
159
|
if isinstance(e, ClassiqInternalExpansionError) or debug_mode.get():
|
|
135
160
|
raise e
|
|
@@ -175,22 +200,56 @@ class BaseInterpreter:
|
|
|
175
200
|
def evaluate(self, expression: Any) -> Evaluated:
|
|
176
201
|
raise NotImplementedError(f"Cannot evaluate {expression!r}")
|
|
177
202
|
|
|
203
|
+
def get_foreign_functions(self) -> dict[str, Callable]:
|
|
204
|
+
return {}
|
|
205
|
+
|
|
178
206
|
@evaluate.register
|
|
179
|
-
def evaluate_classical_expression(
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
207
|
+
def evaluate_classical_expression(
|
|
208
|
+
self,
|
|
209
|
+
expression: Expression,
|
|
210
|
+
*,
|
|
211
|
+
simplify: bool = False,
|
|
212
|
+
treat_qnum_as_float: bool = False,
|
|
213
|
+
) -> Evaluated:
|
|
214
|
+
if expression.is_evaluated():
|
|
215
|
+
return Evaluated(value=expression.value.value)
|
|
216
|
+
expr_ast = ast.parse(expression.expr, mode="eval").body
|
|
217
|
+
expr_ast = QmodExpressionBwc().visit(expr_ast)
|
|
218
|
+
expr_val = self._eval_expr(ast.unparse(expr_ast), treat_qnum_as_float)
|
|
219
|
+
if simplify and not expr_val.has_value(expr_val.root):
|
|
220
|
+
simplified_expr = simplify_qmod_expression(expr_val)
|
|
221
|
+
expr_val = self._eval_expr(simplified_expr, treat_qnum_as_float)
|
|
222
|
+
if expr_val.has_value(expr_val.root):
|
|
223
|
+
value = expr_val.get_value(expr_val.root)
|
|
224
|
+
else:
|
|
225
|
+
value = expr_val
|
|
226
|
+
|
|
227
|
+
return Evaluated(value=value)
|
|
228
|
+
|
|
229
|
+
def _eval_expr(
|
|
230
|
+
self, expr: str, treat_qnum_as_float: bool
|
|
231
|
+
) -> QmodAnnotatedExpression:
|
|
232
|
+
return evaluate_qmod_expression(
|
|
233
|
+
expr,
|
|
234
|
+
treat_qnum_as_float=treat_qnum_as_float,
|
|
235
|
+
machine_precision=self._model.preferences.machine_precision,
|
|
236
|
+
classical_struct_declarations=list(QMODULE.type_decls.values()),
|
|
237
|
+
enum_declarations=list(QMODULE.enum_decls.values()),
|
|
238
|
+
classical_function_declarations=list(
|
|
239
|
+
ClassicalFunctionDeclaration.FOREIGN_FUNCTION_DECLARATIONS.values()
|
|
240
|
+
),
|
|
241
|
+
classical_function_callables=self.get_foreign_functions(),
|
|
242
|
+
scope={
|
|
243
|
+
name: processed_val
|
|
244
|
+
for name in list(self._builder.current_scope)
|
|
187
245
|
if (
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
246
|
+
processed_val := process_scope_val(
|
|
247
|
+
self._builder.current_scope[name].value
|
|
248
|
+
)
|
|
249
|
+
)
|
|
250
|
+
is not None
|
|
251
|
+
},
|
|
252
|
+
)
|
|
194
253
|
|
|
195
254
|
@evaluate.register
|
|
196
255
|
def evaluate_identifier(self, identifier: str) -> Evaluated:
|
|
@@ -216,6 +275,8 @@ class BaseInterpreter:
|
|
|
216
275
|
)
|
|
217
276
|
start = self.evaluate(sliced_handle_binding.start).value
|
|
218
277
|
end = self.evaluate(sliced_handle_binding.end).value
|
|
278
|
+
_validate_index(start, "Slice")
|
|
279
|
+
_validate_index(end, "Slice")
|
|
219
280
|
return Evaluated(value=quantum_variable[start:end])
|
|
220
281
|
|
|
221
282
|
@evaluate.register
|
|
@@ -232,6 +293,7 @@ class BaseInterpreter:
|
|
|
232
293
|
def evaluate_subscript_operand(self, subscript: OperandIdentifier) -> Evaluated:
|
|
233
294
|
base_value = self.evaluate(subscript.name)
|
|
234
295
|
index_value = self.evaluate(subscript.index).as_type(int)
|
|
296
|
+
_validate_index(index_value, "Array")
|
|
235
297
|
return Evaluated(value=base_value.value[index_value])
|
|
236
298
|
|
|
237
299
|
@evaluate.register
|
|
@@ -4,8 +4,6 @@ import os
|
|
|
4
4
|
from pydantic import ValidationError
|
|
5
5
|
|
|
6
6
|
from classiq.interface.exceptions import ClassiqError
|
|
7
|
-
from classiq.interface.model.allocate import Allocate
|
|
8
|
-
from classiq.interface.model.bind_operation import BindOperation
|
|
9
7
|
from classiq.interface.model.quantum_function_call import QuantumFunctionCall
|
|
10
8
|
from classiq.interface.source_reference import SourceReference
|
|
11
9
|
|
|
@@ -13,8 +11,6 @@ from classiq.model_expansions.closure import FunctionClosure, GenerativeFunction
|
|
|
13
11
|
from classiq.model_expansions.interpreters.generative_interpreter import (
|
|
14
12
|
GenerativeInterpreter,
|
|
15
13
|
)
|
|
16
|
-
from classiq.model_expansions.quantum_operations import BindEmitter
|
|
17
|
-
from classiq.model_expansions.quantum_operations.allocate import AllocateEmitter
|
|
18
14
|
from classiq.model_expansions.quantum_operations.quantum_function_call import (
|
|
19
15
|
DeclarativeQuantumFunctionCallEmitter,
|
|
20
16
|
)
|
|
@@ -23,12 +19,6 @@ from classiq.qmod.model_state_container import QMODULE
|
|
|
23
19
|
|
|
24
20
|
|
|
25
21
|
class FrontendGenerativeInterpreter(GenerativeInterpreter):
|
|
26
|
-
def emit_allocate(self, allocate: Allocate) -> None:
|
|
27
|
-
AllocateEmitter(self, allow_symbolic_attrs=True).emit(allocate)
|
|
28
|
-
|
|
29
|
-
def emit_bind(self, bind: BindOperation) -> None:
|
|
30
|
-
BindEmitter(self, allow_symbolic_size=True).emit(bind)
|
|
31
|
-
|
|
32
22
|
def emit_quantum_function_call(self, call: QuantumFunctionCall) -> None:
|
|
33
23
|
DeclarativeQuantumFunctionCallEmitter(self).emit(call)
|
|
34
24
|
|
|
@@ -45,7 +35,7 @@ class FrontendGenerativeInterpreter(GenerativeInterpreter):
|
|
|
45
35
|
return super()._get_main_closure(main_func)
|
|
46
36
|
|
|
47
37
|
def process_exception(self, e: Exception) -> None:
|
|
48
|
-
if not isinstance(e, (ClassiqError, ValidationError)):
|
|
38
|
+
if not isinstance(e, (ClassiqError, ValidationError, RecursionError)):
|
|
49
39
|
frame = inspect.trace()[-1]
|
|
50
40
|
module = inspect.getmodule(frame[0])
|
|
51
41
|
if module is None or not module.__name__.startswith("classiq."):
|
|
@@ -11,6 +11,7 @@ from classiq.interface.generator.functions.builtins.internal_operators import (
|
|
|
11
11
|
CLASSICAL_IF_OPERATOR_NAME,
|
|
12
12
|
CONTROL_OPERATOR_NAME,
|
|
13
13
|
INVERT_OPERATOR_NAME,
|
|
14
|
+
POWER_OPERATOR_NAME,
|
|
14
15
|
REPEAT_OPERATOR_NAME,
|
|
15
16
|
WITHIN_APPLY_NAME,
|
|
16
17
|
)
|
|
@@ -108,6 +109,7 @@ class GenerativeInterpreter(BaseInterpreter):
|
|
|
108
109
|
self.infer_symbolic_parameters(
|
|
109
110
|
model.functions, [gen_func.func_decl for gen_func in generative_functions]
|
|
110
111
|
)
|
|
112
|
+
self._symbolic_parameters_switch = self.allow_symbolic_parameters()
|
|
111
113
|
|
|
112
114
|
def infer_symbolic_parameters(
|
|
113
115
|
self,
|
|
@@ -118,6 +120,9 @@ class GenerativeInterpreter(BaseInterpreter):
|
|
|
118
120
|
) -> None:
|
|
119
121
|
pass
|
|
120
122
|
|
|
123
|
+
def allow_symbolic_parameters(self) -> bool:
|
|
124
|
+
return True
|
|
125
|
+
|
|
121
126
|
def evaluate_lambda(self, function: QuantumLambdaFunction) -> Evaluated:
|
|
122
127
|
func_decl = NamedParamsQuantumFunctionDeclaration(
|
|
123
128
|
name=self._counted_name_allocator.allocate(
|
|
@@ -164,18 +169,28 @@ class GenerativeInterpreter(BaseInterpreter):
|
|
|
164
169
|
QuantumFunctionCallEmitter(self).emit(call)
|
|
165
170
|
|
|
166
171
|
@emit.register
|
|
167
|
-
def _emit_allocate(self, allocate: Allocate) -> None:
|
|
168
|
-
return self.emit_allocate(allocate)
|
|
169
|
-
|
|
170
172
|
def emit_allocate(self, allocate: Allocate) -> None:
|
|
171
|
-
|
|
173
|
+
CompositeEmitter[Allocate](
|
|
174
|
+
self,
|
|
175
|
+
[
|
|
176
|
+
ExpressionEvaluator(
|
|
177
|
+
self,
|
|
178
|
+
"size",
|
|
179
|
+
readable_expression_name="allocation size",
|
|
180
|
+
allow_link_time_vars=self._symbolic_parameters_switch,
|
|
181
|
+
allow_runtime_vars=self._symbolic_parameters_switch,
|
|
182
|
+
),
|
|
183
|
+
AllocateEmitter(
|
|
184
|
+
self, allow_symbolic_attrs=self._symbolic_parameters_switch
|
|
185
|
+
),
|
|
186
|
+
],
|
|
187
|
+
).emit(allocate)
|
|
172
188
|
|
|
173
189
|
@emit.register
|
|
174
|
-
def _emit_bind(self, bind: BindOperation) -> None:
|
|
175
|
-
self.emit_bind(bind)
|
|
176
|
-
|
|
177
190
|
def emit_bind(self, bind: BindOperation) -> None:
|
|
178
|
-
BindEmitter(self).emit(
|
|
191
|
+
BindEmitter(self, allow_symbolic_size=self._symbolic_parameters_switch).emit(
|
|
192
|
+
bind
|
|
193
|
+
)
|
|
179
194
|
|
|
180
195
|
@emit.register
|
|
181
196
|
def emit_amplitude_loading_operation(self, op: AmplitudeLoadingOperation) -> None:
|
|
@@ -183,7 +198,14 @@ class GenerativeInterpreter(BaseInterpreter):
|
|
|
183
198
|
self,
|
|
184
199
|
[
|
|
185
200
|
HandleEvaluator(self, "result_var"),
|
|
186
|
-
ExpressionEvaluator(
|
|
201
|
+
ExpressionEvaluator(
|
|
202
|
+
self,
|
|
203
|
+
"expression",
|
|
204
|
+
readable_expression_name="amplitude-encoding expression",
|
|
205
|
+
simplify=True,
|
|
206
|
+
treat_qnum_as_float=True,
|
|
207
|
+
allow_runtime_vars=self._symbolic_parameters_switch,
|
|
208
|
+
),
|
|
187
209
|
AssignmentResultProcessor(self),
|
|
188
210
|
],
|
|
189
211
|
).emit(op)
|
|
@@ -197,7 +219,7 @@ class GenerativeInterpreter(BaseInterpreter):
|
|
|
197
219
|
self,
|
|
198
220
|
[
|
|
199
221
|
HandleEvaluator(self, "result_var"),
|
|
200
|
-
ExpressionEvaluator(self, "expression"),
|
|
222
|
+
ExpressionEvaluator(self, "expression", simplify=True),
|
|
201
223
|
ClassicalVarEmitter(self),
|
|
202
224
|
AssignmentResultProcessor(self),
|
|
203
225
|
],
|
|
@@ -210,7 +232,7 @@ class GenerativeInterpreter(BaseInterpreter):
|
|
|
210
232
|
[
|
|
211
233
|
HandleEvaluator(self, "target"),
|
|
212
234
|
HandleEvaluator(self, "value"),
|
|
213
|
-
ExpressionEvaluator(self, "value"),
|
|
235
|
+
ExpressionEvaluator(self, "value", simplify=True),
|
|
214
236
|
],
|
|
215
237
|
).emit(op)
|
|
216
238
|
|
|
@@ -221,14 +243,16 @@ class GenerativeInterpreter(BaseInterpreter):
|
|
|
221
243
|
VariableDeclarationStatementEmitter(self).emit(variable_declaration)
|
|
222
244
|
|
|
223
245
|
@emit.register
|
|
224
|
-
def _emit_classical_if(self, classical_if: ClassicalIf) -> None:
|
|
225
|
-
self.emit_classical_if(classical_if)
|
|
226
|
-
|
|
227
246
|
def emit_classical_if(self, classical_if: ClassicalIf) -> None:
|
|
228
247
|
CompositeEmitter[ClassicalIf](
|
|
229
248
|
self,
|
|
230
249
|
[
|
|
231
|
-
ExpressionEvaluator(
|
|
250
|
+
ExpressionEvaluator(
|
|
251
|
+
self,
|
|
252
|
+
"condition",
|
|
253
|
+
readable_expression_name="classical-if condition",
|
|
254
|
+
allow_link_time_vars=self._symbolic_parameters_switch,
|
|
255
|
+
),
|
|
232
256
|
IfElimination(self),
|
|
233
257
|
BlockEvaluator(
|
|
234
258
|
self,
|
|
@@ -276,7 +300,14 @@ class GenerativeInterpreter(BaseInterpreter):
|
|
|
276
300
|
CompositeEmitter[Control](
|
|
277
301
|
self,
|
|
278
302
|
[
|
|
279
|
-
ExpressionEvaluator(
|
|
303
|
+
ExpressionEvaluator(
|
|
304
|
+
self,
|
|
305
|
+
"expression",
|
|
306
|
+
simplify=True,
|
|
307
|
+
readable_expression_name="control expression",
|
|
308
|
+
allow_link_time_vars=self._symbolic_parameters_switch,
|
|
309
|
+
allow_runtime_vars=self._symbolic_parameters_switch,
|
|
310
|
+
),
|
|
280
311
|
BlockEvaluator(
|
|
281
312
|
self,
|
|
282
313
|
CONTROL_OPERATOR_NAME,
|
|
@@ -291,8 +322,13 @@ class GenerativeInterpreter(BaseInterpreter):
|
|
|
291
322
|
CompositeEmitter[Power](
|
|
292
323
|
self,
|
|
293
324
|
[
|
|
294
|
-
ExpressionEvaluator(
|
|
295
|
-
|
|
325
|
+
ExpressionEvaluator(
|
|
326
|
+
self,
|
|
327
|
+
"power",
|
|
328
|
+
readable_expression_name="power exponent",
|
|
329
|
+
allow_runtime_vars=self._symbolic_parameters_switch,
|
|
330
|
+
),
|
|
331
|
+
BlockEvaluator(self, POWER_OPERATOR_NAME, "body"),
|
|
296
332
|
],
|
|
297
333
|
).emit(power)
|
|
298
334
|
|
|
@@ -301,8 +337,19 @@ class GenerativeInterpreter(BaseInterpreter):
|
|
|
301
337
|
CompositeEmitter[PhaseOperation](
|
|
302
338
|
self,
|
|
303
339
|
[
|
|
304
|
-
ExpressionEvaluator(
|
|
305
|
-
|
|
340
|
+
ExpressionEvaluator(
|
|
341
|
+
self,
|
|
342
|
+
"expression",
|
|
343
|
+
readable_expression_name="phase expression",
|
|
344
|
+
simplify=True,
|
|
345
|
+
allow_runtime_vars=self._symbolic_parameters_switch,
|
|
346
|
+
),
|
|
347
|
+
ExpressionEvaluator(
|
|
348
|
+
self,
|
|
349
|
+
"theta",
|
|
350
|
+
readable_expression_name="phase theta expression",
|
|
351
|
+
allow_runtime_vars=self._symbolic_parameters_switch,
|
|
352
|
+
),
|
|
306
353
|
],
|
|
307
354
|
).emit(phase)
|
|
308
355
|
|
|
@@ -1,10 +1,16 @@
|
|
|
1
|
-
from typing import TYPE_CHECKING, Union
|
|
1
|
+
from typing import TYPE_CHECKING, Any, Union
|
|
2
2
|
|
|
3
3
|
import sympy
|
|
4
4
|
|
|
5
5
|
from classiq.interface.debug_info.debug_info import FunctionDebugInfo
|
|
6
6
|
from classiq.interface.exceptions import ClassiqExpansionError, ClassiqValueError
|
|
7
|
+
from classiq.interface.generator.expressions.evaluated_expression import (
|
|
8
|
+
EvaluatedExpression,
|
|
9
|
+
)
|
|
7
10
|
from classiq.interface.generator.expressions.expression import Expression
|
|
11
|
+
from classiq.interface.generator.expressions.expression_types import ExpressionValue
|
|
12
|
+
from classiq.interface.generator.functions.classical_type import Bool, Integer, Real
|
|
13
|
+
from classiq.interface.helpers.text_utils import s
|
|
8
14
|
from classiq.interface.model.allocate import Allocate
|
|
9
15
|
from classiq.interface.model.handle_binding import NestedHandleBinding
|
|
10
16
|
from classiq.interface.model.quantum_type import (
|
|
@@ -12,6 +18,8 @@ from classiq.interface.model.quantum_type import (
|
|
|
12
18
|
QuantumNumeric,
|
|
13
19
|
)
|
|
14
20
|
|
|
21
|
+
from classiq.evaluators.qmod_annotated_expression import QmodAnnotatedExpression
|
|
22
|
+
from classiq.evaluators.qmod_node_evaluators.utils import get_sympy_type
|
|
15
23
|
from classiq.evaluators.qmod_type_inference.quantum_type_inference import (
|
|
16
24
|
inject_quantum_type_attributes_inplace,
|
|
17
25
|
)
|
|
@@ -22,6 +30,13 @@ if TYPE_CHECKING:
|
|
|
22
30
|
from classiq.model_expansions.interpreters.base_interpreter import BaseInterpreter
|
|
23
31
|
|
|
24
32
|
|
|
33
|
+
def _assign_attr(
|
|
34
|
+
op_update_dict: dict[str, Expression], attr: str, size_value: ExpressionValue
|
|
35
|
+
) -> None:
|
|
36
|
+
op_update_dict[attr] = Expression(expr=str(size_value))
|
|
37
|
+
op_update_dict[attr]._evaluated_expr = EvaluatedExpression(value=size_value)
|
|
38
|
+
|
|
39
|
+
|
|
25
40
|
class AllocateEmitter(Emitter[Allocate]):
|
|
26
41
|
def __init__(
|
|
27
42
|
self, interpreter: "BaseInterpreter", allow_symbolic_attrs: bool = False
|
|
@@ -86,7 +101,7 @@ class AllocateEmitter(Emitter[Allocate]):
|
|
|
86
101
|
raise ClassiqValueError(
|
|
87
102
|
f"Could not infer the size of variable {str(target.handle)!r}"
|
|
88
103
|
)
|
|
89
|
-
op_update_dict["size"] = Expression(expr=expr)
|
|
104
|
+
op_update_dict["size"] = self._evaluate_expression(Expression(expr=expr))
|
|
90
105
|
|
|
91
106
|
def _handle_with_size(
|
|
92
107
|
self,
|
|
@@ -95,10 +110,10 @@ class AllocateEmitter(Emitter[Allocate]):
|
|
|
95
110
|
op_update_dict: dict[str, Expression],
|
|
96
111
|
) -> None:
|
|
97
112
|
size_value = self._interpret_size(size, str(target.handle))
|
|
98
|
-
op_update_dict
|
|
113
|
+
_assign_attr(op_update_dict, "size", size_value)
|
|
99
114
|
|
|
100
115
|
if not isinstance(
|
|
101
|
-
size_value,
|
|
116
|
+
size_value, QmodAnnotatedExpression
|
|
102
117
|
) and not inject_quantum_type_attributes_inplace(
|
|
103
118
|
QuantumBitvector(length=op_update_dict["size"]), target.quantum_type
|
|
104
119
|
):
|
|
@@ -122,16 +137,19 @@ class AllocateEmitter(Emitter[Allocate]):
|
|
|
122
137
|
)
|
|
123
138
|
|
|
124
139
|
size_value = self._interpret_size(size, var_name)
|
|
125
|
-
op_update_dict
|
|
140
|
+
_assign_attr(op_update_dict, "size", size_value)
|
|
126
141
|
is_signed_value = self._interpret_is_signed(is_signed)
|
|
127
|
-
op_update_dict
|
|
142
|
+
_assign_attr(op_update_dict, "is_signed", is_signed_value)
|
|
128
143
|
fraction_digits_value = self._interpret_fraction_digits(fraction_digits)
|
|
129
|
-
op_update_dict
|
|
144
|
+
_assign_attr(op_update_dict, "fraction_digits", fraction_digits_value)
|
|
145
|
+
self._validate_numeric_atrributes(
|
|
146
|
+
var_name, size_value, is_signed_value, fraction_digits_value
|
|
147
|
+
)
|
|
130
148
|
|
|
131
149
|
if not (
|
|
132
|
-
isinstance(size_value,
|
|
133
|
-
or isinstance(is_signed_value,
|
|
134
|
-
or isinstance(fraction_digits_value,
|
|
150
|
+
isinstance(size_value, QmodAnnotatedExpression)
|
|
151
|
+
or isinstance(is_signed_value, QmodAnnotatedExpression)
|
|
152
|
+
or isinstance(fraction_digits_value, QmodAnnotatedExpression)
|
|
135
153
|
) and not inject_quantum_type_attributes_inplace(
|
|
136
154
|
QuantumNumeric(
|
|
137
155
|
size=op_update_dict["size"],
|
|
@@ -145,24 +163,73 @@ class AllocateEmitter(Emitter[Allocate]):
|
|
|
145
163
|
f"{var_name!r} of type {target.quantum_type.qmod_type_name}"
|
|
146
164
|
)
|
|
147
165
|
|
|
166
|
+
def _validate_numeric_atrributes(
|
|
167
|
+
self,
|
|
168
|
+
var_name: str,
|
|
169
|
+
size_value: Any,
|
|
170
|
+
is_signed_value: Any,
|
|
171
|
+
fraction_digits_value: Any,
|
|
172
|
+
) -> None:
|
|
173
|
+
if (
|
|
174
|
+
isinstance(size_value, int)
|
|
175
|
+
and isinstance(is_signed_value, bool)
|
|
176
|
+
and isinstance(fraction_digits_value, int)
|
|
177
|
+
):
|
|
178
|
+
if size_value < 0:
|
|
179
|
+
raise ClassiqValueError(
|
|
180
|
+
f"Cannot allocate {size_value} qubit{s(size_value)} for variable "
|
|
181
|
+
f"{var_name!r}"
|
|
182
|
+
)
|
|
183
|
+
if fraction_digits_value < 0:
|
|
184
|
+
raise ClassiqValueError(
|
|
185
|
+
f"Variable {var_name!r} cannot have a negative number of fraction "
|
|
186
|
+
f"digits (got {fraction_digits_value})"
|
|
187
|
+
)
|
|
188
|
+
if size_value < fraction_digits_value:
|
|
189
|
+
raise ClassiqValueError(
|
|
190
|
+
f"Cannot allocate {size_value} qubit{s(size_value)} for variable "
|
|
191
|
+
f"{var_name!r} with {fraction_digits_value} fraction digits"
|
|
192
|
+
)
|
|
193
|
+
|
|
148
194
|
def _interpret_size(
|
|
149
195
|
self, size: Expression, var_name: str
|
|
150
|
-
) -> Union[int, float, sympy.Basic]:
|
|
196
|
+
) -> Union[int, float, sympy.Basic, QmodAnnotatedExpression]:
|
|
151
197
|
size_value = self._interpreter.evaluate(size).value
|
|
152
|
-
if not
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
198
|
+
if not (
|
|
199
|
+
(
|
|
200
|
+
isinstance(size_value, QmodAnnotatedExpression)
|
|
201
|
+
and isinstance(size_value.get_type(size_value.root), (Integer, Real))
|
|
202
|
+
)
|
|
203
|
+
or isinstance(size_value, (int, float))
|
|
204
|
+
or (
|
|
205
|
+
isinstance(size_value, sympy.Basic)
|
|
206
|
+
and isinstance(get_sympy_type(size_value), (Integer, Real))
|
|
207
|
+
)
|
|
208
|
+
):
|
|
157
209
|
raise ClassiqValueError(
|
|
158
210
|
f"The number of allocated qubits must be an integer. Got "
|
|
159
211
|
f"{str(size_value)!r}"
|
|
160
212
|
)
|
|
213
|
+
if (
|
|
214
|
+
isinstance(size_value, QmodAnnotatedExpression)
|
|
215
|
+
and not self._allow_symbolic_attrs
|
|
216
|
+
):
|
|
217
|
+
raise ClassiqValueError(
|
|
218
|
+
f"Could not infer the size of variable {var_name!r}"
|
|
219
|
+
)
|
|
161
220
|
return size_value
|
|
162
221
|
|
|
163
|
-
def _interpret_is_signed(
|
|
222
|
+
def _interpret_is_signed(
|
|
223
|
+
self, is_signed: Expression
|
|
224
|
+
) -> Union[bool, sympy.Basic, QmodAnnotatedExpression]:
|
|
164
225
|
is_signed_value = self._interpreter.evaluate(is_signed).value
|
|
165
|
-
if not self._allow_symbolic_attrs and not
|
|
226
|
+
if not self._allow_symbolic_attrs and not (
|
|
227
|
+
isinstance(is_signed_value, bool)
|
|
228
|
+
or (
|
|
229
|
+
isinstance(is_signed_value, sympy.Basic)
|
|
230
|
+
and isinstance(get_sympy_type(is_signed_value), Bool)
|
|
231
|
+
)
|
|
232
|
+
):
|
|
166
233
|
raise ClassiqValueError(
|
|
167
234
|
f"The sign of a variable must be boolean. Got "
|
|
168
235
|
f"{str(is_signed_value)!r}"
|
|
@@ -171,10 +238,14 @@ class AllocateEmitter(Emitter[Allocate]):
|
|
|
171
238
|
|
|
172
239
|
def _interpret_fraction_digits(
|
|
173
240
|
self, fraction_digits: Expression
|
|
174
|
-
) -> Union[int, float, sympy.
|
|
241
|
+
) -> Union[int, float, sympy.Expr, QmodAnnotatedExpression]:
|
|
175
242
|
fraction_digits_value = self._interpreter.evaluate(fraction_digits).value
|
|
176
|
-
if not self._allow_symbolic_attrs and not
|
|
177
|
-
fraction_digits_value, (int, float)
|
|
243
|
+
if not self._allow_symbolic_attrs and not (
|
|
244
|
+
isinstance(fraction_digits_value, (int, float))
|
|
245
|
+
or (
|
|
246
|
+
isinstance(fraction_digits_value, sympy.Expr)
|
|
247
|
+
and fraction_digits_value.is_integer
|
|
248
|
+
)
|
|
178
249
|
):
|
|
179
250
|
raise ClassiqValueError(
|
|
180
251
|
f"The fraction digits of a variable must be an integer. Got "
|
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
from typing import TYPE_CHECKING, Optional
|
|
2
2
|
|
|
3
3
|
from classiq.interface.exceptions import ClassiqExpansionError
|
|
4
|
-
from classiq.interface.generator.arith.arithmetic import compute_arithmetic_result_type
|
|
5
4
|
from classiq.interface.generator.expressions.expression import Expression
|
|
6
5
|
from classiq.interface.model.allocate import Allocate
|
|
7
6
|
from classiq.interface.model.bind_operation import BindOperation
|
|
@@ -20,23 +19,31 @@ from classiq.interface.model.quantum_expressions.quantum_expression import (
|
|
|
20
19
|
QuantumAssignmentOperation,
|
|
21
20
|
)
|
|
22
21
|
from classiq.interface.model.quantum_function_call import QuantumFunctionCall
|
|
23
|
-
from classiq.interface.model.quantum_type import
|
|
22
|
+
from classiq.interface.model.quantum_type import (
|
|
23
|
+
QuantumBitvector,
|
|
24
|
+
QuantumNumeric,
|
|
25
|
+
QuantumScalar,
|
|
26
|
+
)
|
|
24
27
|
from classiq.interface.model.statement_block import StatementBlock
|
|
25
28
|
from classiq.interface.model.variable_declaration_statement import (
|
|
26
29
|
VariableDeclarationStatement,
|
|
27
30
|
)
|
|
28
31
|
from classiq.interface.model.within_apply_operation import WithinApply
|
|
29
32
|
|
|
33
|
+
from classiq.evaluators.qmod_annotated_expression import QmodAnnotatedExpression
|
|
30
34
|
from classiq.evaluators.qmod_type_inference.quantum_type_inference import (
|
|
31
35
|
inject_quantum_type_attributes_inplace,
|
|
32
36
|
)
|
|
37
|
+
from classiq.model_expansions.arithmetic import NumericAttributes
|
|
38
|
+
from classiq.model_expansions.arithmetic_compute_result_attrs import (
|
|
39
|
+
compute_result_attrs_assign,
|
|
40
|
+
)
|
|
33
41
|
from classiq.model_expansions.quantum_operations.arithmetic.explicit_boolean_expressions import (
|
|
34
42
|
convert_assignment_bool_expression,
|
|
35
43
|
validate_assignment_bool_expression,
|
|
36
44
|
)
|
|
37
45
|
from classiq.model_expansions.quantum_operations.emitter import Emitter
|
|
38
46
|
from classiq.model_expansions.scope import ClassicalSymbol
|
|
39
|
-
from classiq.model_expansions.transformers.ast_renamer import rename_variables
|
|
40
47
|
from classiq.qmod.builtins.functions.standard_gates import CX
|
|
41
48
|
|
|
42
49
|
if TYPE_CHECKING:
|
|
@@ -100,33 +107,27 @@ class AssignmentResultProcessor(Emitter[QuantumAssignmentOperation]):
|
|
|
100
107
|
|
|
101
108
|
def _infer_expression_type(
|
|
102
109
|
self, op: ArithmeticOperation
|
|
103
|
-
) -> Optional[
|
|
110
|
+
) -> Optional[QuantumScalar]:
|
|
104
111
|
expr = self._evaluate_expression(op.expression)
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
112
|
+
expr_val = expr.value.value
|
|
113
|
+
if isinstance(expr_val, QmodAnnotatedExpression):
|
|
114
|
+
root_type = expr_val.get_type(expr_val.root)
|
|
115
|
+
if isinstance(root_type, QuantumScalar) and root_type.is_instantiated:
|
|
116
|
+
root_type = compute_result_attrs_assign(
|
|
117
|
+
NumericAttributes.from_type_or_constant(root_type),
|
|
118
|
+
self._machine_precision,
|
|
119
|
+
).to_quantum_numeric()
|
|
120
|
+
return root_type
|
|
110
121
|
return None
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
)
|
|
117
|
-
for symbol in symbols:
|
|
118
|
-
expr_str = expr_str.replace(
|
|
119
|
-
symbol.handle.qmod_expr, symbol.handle.identifier
|
|
120
|
-
)
|
|
121
|
-
return compute_arithmetic_result_type(
|
|
122
|
-
expr_str,
|
|
123
|
-
{symbol.handle.identifier: symbol.quantum_type for symbol in symbols},
|
|
124
|
-
self._machine_precision,
|
|
125
|
-
)
|
|
122
|
+
if isinstance(expr_val, (int, float)):
|
|
123
|
+
return NumericAttributes.from_constant(
|
|
124
|
+
expr_val, self._machine_precision
|
|
125
|
+
).to_quantum_numeric()
|
|
126
|
+
return None
|
|
126
127
|
|
|
127
128
|
@staticmethod
|
|
128
129
|
def _same_numeric_attributes(
|
|
129
|
-
result_type: QuantumNumeric, expression_type:
|
|
130
|
+
result_type: QuantumNumeric, expression_type: QuantumScalar
|
|
130
131
|
) -> bool:
|
|
131
132
|
return (
|
|
132
133
|
result_type.size_in_bits == expression_type.size_in_bits
|
|
@@ -137,7 +138,7 @@ class AssignmentResultProcessor(Emitter[QuantumAssignmentOperation]):
|
|
|
137
138
|
|
|
138
139
|
@classmethod
|
|
139
140
|
def _validate_declared_attributes(
|
|
140
|
-
cls, result_type: QuantumNumeric, expression_type:
|
|
141
|
+
cls, result_type: QuantumNumeric, expression_type: QuantumScalar, var: str
|
|
141
142
|
) -> None:
|
|
142
143
|
result_size, result_sign, result_fractions = (
|
|
143
144
|
result_type.size_in_bits,
|
|
@@ -183,7 +184,7 @@ class AssignmentResultProcessor(Emitter[QuantumAssignmentOperation]):
|
|
|
183
184
|
self,
|
|
184
185
|
op: ArithmeticOperation,
|
|
185
186
|
result_type: QuantumNumeric,
|
|
186
|
-
expression_type:
|
|
187
|
+
expression_type: QuantumScalar,
|
|
187
188
|
) -> None:
|
|
188
189
|
stmts: StatementBlock = []
|
|
189
190
|
handles: list[HandleBinding] = []
|