classiq 0.75.0__py3-none-any.whl → 0.76.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.
- classiq/_internals/api_wrapper.py +36 -0
- classiq/analyzer/show_interactive_hack.py +58 -2
- classiq/applications/chemistry/chemistry_model_constructor.py +8 -1
- classiq/applications/combinatorial_optimization/combinatorial_optimization_model_constructor.py +2 -0
- classiq/applications/combinatorial_optimization/combinatorial_problem.py +4 -4
- classiq/applications/qnn/gradients/quantum_gradient.py +3 -5
- classiq/applications/qnn/gradients/simple_quantum_gradient.py +2 -2
- classiq/applications/qnn/qlayer.py +14 -19
- classiq/applications/qnn/types.py +1 -4
- classiq/execution/__init__.py +3 -0
- classiq/execution/execution_session.py +3 -16
- classiq/execution/qnn.py +2 -2
- classiq/execution/user_budgets.py +38 -0
- classiq/executor.py +7 -19
- classiq/interface/_version.py +1 -1
- classiq/interface/debug_info/debug_info.py +16 -2
- classiq/interface/executor/user_budget.py +56 -0
- classiq/interface/generator/application_apis/finance_declarations.py +3 -0
- classiq/interface/generator/expressions/atomic_expression_functions.py +3 -0
- classiq/interface/generator/expressions/proxies/classical/any_classical_value.py +30 -124
- classiq/interface/generator/expressions/proxies/classical/classical_array_proxy.py +45 -21
- classiq/interface/generator/expressions/proxies/classical/qmod_struct_instance.py +7 -0
- classiq/interface/generator/expressions/proxies/classical/utils.py +12 -11
- classiq/interface/generator/expressions/proxies/quantum/qmod_qscalar_proxy.py +9 -2
- classiq/interface/generator/expressions/proxies/quantum/qmod_sized_proxy.py +4 -1
- classiq/interface/generator/expressions/sympy_supported_expressions.py +1 -0
- classiq/interface/generator/functions/classical_type.py +6 -1
- classiq/interface/generator/functions/type_name.py +7 -2
- classiq/interface/generator/functions/type_qualifier.py +15 -0
- classiq/interface/generator/model/preferences/preferences.py +7 -0
- classiq/interface/generator/quantum_program.py +5 -19
- classiq/interface/helpers/backward_compatibility.py +9 -0
- classiq/interface/helpers/datastructures.py +6 -0
- classiq/interface/model/port_declaration.py +1 -2
- classiq/interface/model/quantum_lambda_function.py +2 -1
- classiq/interface/server/routes.py +6 -0
- classiq/model_expansions/atomic_expression_functions_defs.py +62 -19
- classiq/model_expansions/capturing/captured_vars.py +2 -0
- classiq/model_expansions/closure.py +5 -0
- classiq/model_expansions/evaluators/classical_type_inference.py +17 -6
- classiq/model_expansions/evaluators/parameter_types.py +26 -13
- classiq/model_expansions/expression_evaluator.py +1 -1
- classiq/model_expansions/generative_functions.py +61 -34
- classiq/model_expansions/interpreters/base_interpreter.py +17 -6
- classiq/model_expansions/interpreters/frontend_generative_interpreter.py +5 -0
- classiq/model_expansions/interpreters/generative_interpreter.py +13 -1
- classiq/model_expansions/quantum_operations/allocate.py +6 -1
- classiq/model_expansions/quantum_operations/assignment_result_processor.py +219 -20
- classiq/model_expansions/quantum_operations/bind.py +54 -30
- classiq/model_expansions/quantum_operations/block_evaluator.py +42 -0
- classiq/model_expansions/quantum_operations/call_emitter.py +14 -7
- classiq/model_expansions/quantum_operations/composite_emitter.py +1 -1
- classiq/model_expansions/quantum_operations/declarative_call_emitter.py +23 -9
- classiq/model_expansions/quantum_operations/emitter.py +20 -3
- classiq/model_expansions/quantum_operations/quantum_function_call.py +4 -3
- classiq/model_expansions/scope.py +10 -7
- classiq/model_expansions/sympy_conversion/arithmetics.py +18 -0
- classiq/model_expansions/sympy_conversion/expression_to_sympy.py +2 -0
- classiq/model_expansions/sympy_conversion/sympy_to_python.py +10 -1
- classiq/model_expansions/transformers/model_renamer.py +45 -7
- classiq/model_expansions/utils/handles_collector.py +1 -1
- classiq/model_expansions/visitors/variable_references.py +45 -9
- classiq/qmod/builtins/functions/allocation.py +2 -2
- classiq/qmod/builtins/functions/arithmetic.py +14 -12
- classiq/qmod/builtins/functions/standard_gates.py +23 -23
- classiq/qmod/declaration_inferrer.py +19 -7
- classiq/qmod/generative.py +9 -1
- classiq/qmod/native/expression_to_qmod.py +4 -0
- classiq/qmod/native/pretty_printer.py +8 -3
- classiq/qmod/pretty_print/pretty_printer.py +1 -1
- classiq/qmod/python_classical_type.py +4 -5
- classiq/qmod/qmod_constant.py +15 -7
- classiq/qmod/qmod_variable.py +7 -1
- classiq/qmod/quantum_function.py +19 -6
- classiq/qmod/semantics/lambdas.py +6 -2
- classiq/qmod/semantics/validation/main_validation.py +17 -4
- classiq/qmod/symbolic.py +8 -19
- classiq/qmod/symbolic_expr.py +26 -0
- classiq/synthesis.py +17 -31
- classiq/visualization.py +35 -0
- {classiq-0.75.0.dist-info → classiq-0.76.0.dist-info}/METADATA +1 -1
- {classiq-0.75.0.dist-info → classiq-0.76.0.dist-info}/RECORD +83 -79
- {classiq-0.75.0.dist-info → classiq-0.76.0.dist-info}/WHEEL +0 -0
@@ -5,6 +5,7 @@ import pydantic
|
|
5
5
|
from classiq.interface.ast_node import ASTNode
|
6
6
|
from classiq.interface.exceptions import ClassiqError
|
7
7
|
from classiq.interface.generator.expressions.expression import Expression
|
8
|
+
from classiq.interface.helpers.backward_compatibility import zip_strict
|
8
9
|
from classiq.interface.model.quantum_function_declaration import (
|
9
10
|
AnonQuantumOperandDeclaration,
|
10
11
|
)
|
@@ -56,7 +57,7 @@ class QuantumLambdaFunction(ASTNode):
|
|
56
57
|
def named_func_decl(self) -> AnonQuantumOperandDeclaration:
|
57
58
|
named_params = [
|
58
59
|
param.rename(rename)
|
59
|
-
for param, rename in
|
60
|
+
for param, rename in zip_strict(
|
60
61
|
self.func_decl.positional_arg_declarations,
|
61
62
|
self.pos_rename_params,
|
62
63
|
strict=False, # strict=False enables lambda keyword args
|
@@ -6,6 +6,8 @@ CONVERSION_PREFIX = "/conversion"
|
|
6
6
|
PROVIDERS_PREFIX = "/providers"
|
7
7
|
|
8
8
|
IQCC_PREFIX = PROVIDERS_PREFIX + "/iqcc"
|
9
|
+
USER_BUDGETS_PREFIX = "/user_budgets"
|
10
|
+
|
9
11
|
|
10
12
|
ANALYZER_CIRCUIT_PAGE = "circuit"
|
11
13
|
DEFAULT_IDE_FE_APP = "https://platform.classiq.io/"
|
@@ -50,6 +52,7 @@ TASK_TEST_SUFFIX = TASKS_SUFFIX + "/test"
|
|
50
52
|
TASK_PREDICT_SUFFIX = TASKS_SUFFIX + "/predict"
|
51
53
|
TASK_RB_SUFFIX = TASKS_SUFFIX + RB
|
52
54
|
TASKS_GENERATE_FULL_PATH = TASKS_GENERATE_SUFFIX
|
55
|
+
TASKS_VISUAL_MODEL_FULL_PATH = ANALYZER_PREFIX + TASKS_VISUAL_MODEL_SUFFIX
|
53
56
|
|
54
57
|
EXECUTION_JOBS_SUFFIX = "/jobs"
|
55
58
|
EXECUTION_JOBS_FULL_PATH = EXECUTION_PREFIX + EXECUTION_JOBS_SUFFIX
|
@@ -80,3 +83,6 @@ IQCC_LIST_AUTH_METHODS_SUFFIX = "/auth_methods"
|
|
80
83
|
IQCC_LIST_AUTH_METHODS_FULL_PATH = IQCC_PREFIX + IQCC_LIST_AUTH_METHODS_SUFFIX
|
81
84
|
IQCC_LIST_AUTH_TARGETS_SUFFIX = "/auth_targets"
|
82
85
|
IQCC_LIST_AUTH_TARGETS_FULL_PATH = IQCC_PREFIX + IQCC_LIST_AUTH_TARGETS_SUFFIX
|
86
|
+
|
87
|
+
USER_BUDGETS_SUFFIX = "/all"
|
88
|
+
USER_BUDGETS_FULL_PATH = USER_BUDGETS_PREFIX + USER_BUDGETS_SUFFIX
|
@@ -2,6 +2,7 @@ from collections.abc import Mapping
|
|
2
2
|
from enum import Enum
|
3
3
|
from typing import Any, Callable, Union, get_args
|
4
4
|
|
5
|
+
import sympy
|
5
6
|
from sympy import Eq, Expr, Piecewise, Symbol
|
6
7
|
|
7
8
|
from classiq.interface.exceptions import (
|
@@ -56,6 +57,8 @@ from classiq.model_expansions.sympy_conversion.arithmetics import (
|
|
56
57
|
BitwiseOr,
|
57
58
|
BitwiseXor,
|
58
59
|
LogicalXor,
|
60
|
+
LShift,
|
61
|
+
RShift,
|
59
62
|
)
|
60
63
|
from classiq.model_expansions.sympy_conversion.expression_to_sympy import (
|
61
64
|
MISSING_SLICE_VALUE_PLACEHOLDER,
|
@@ -63,11 +66,12 @@ from classiq.model_expansions.sympy_conversion.expression_to_sympy import (
|
|
63
66
|
from classiq.model_expansions.sympy_conversion.sympy_to_python import (
|
64
67
|
sympy_to_python,
|
65
68
|
)
|
66
|
-
from classiq.model_expansions.utils.sympy_utils import
|
67
|
-
|
68
|
-
|
69
|
+
from classiq.model_expansions.utils.sympy_utils import is_constant_subscript
|
70
|
+
from classiq.qmod.builtins.classical_functions import (
|
71
|
+
__all__ as qmod_classical_functions,
|
69
72
|
)
|
70
73
|
from classiq.qmod.model_state_container import QMODULE
|
74
|
+
from classiq.qmod.utilities import qmod_val_to_expr_str
|
71
75
|
|
72
76
|
|
73
77
|
def qmod_val_to_python(val: ExpressionValue, qmod_type: ClassicalType) -> Any:
|
@@ -169,19 +173,14 @@ def get_field(
|
|
169
173
|
],
|
170
174
|
field: str,
|
171
175
|
) -> ExpressionValue:
|
172
|
-
if isinstance(proxy, AnyClassicalValue)
|
173
|
-
return AnyClassicalValue(f"({proxy}).{field}")
|
174
|
-
if isinstance(proxy, type) and issubclass(proxy, Enum):
|
175
|
-
return getattr(proxy, field)
|
176
|
-
if (
|
176
|
+
if isinstance(proxy, AnyClassicalValue) or (
|
177
177
|
isinstance(proxy, Symbol)
|
178
178
|
and not isinstance(proxy, QmodSizedProxy)
|
179
179
|
and not isinstance(proxy, ClassicalProxy)
|
180
180
|
):
|
181
|
-
|
182
|
-
|
183
|
-
|
184
|
-
)
|
181
|
+
return AnyClassicalValue(f"get_field({qmod_val_to_expr_str(proxy)}, '{field}')")
|
182
|
+
if isinstance(proxy, type) and issubclass(proxy, Enum):
|
183
|
+
return getattr(proxy, field)
|
185
184
|
if isinstance(proxy, list):
|
186
185
|
if field != "len":
|
187
186
|
raise ClassiqExpansionError(
|
@@ -217,9 +216,10 @@ def get_type(struct_type: Symbol) -> TypeProxy:
|
|
217
216
|
|
218
217
|
|
219
218
|
def do_div(lhs: Any, rhs: Any) -> Any:
|
220
|
-
|
221
|
-
|
222
|
-
|
219
|
+
res = lhs / rhs
|
220
|
+
if isinstance(res, sympy.Expr):
|
221
|
+
res = res.evalf()
|
222
|
+
return res
|
223
223
|
|
224
224
|
|
225
225
|
_EXPRESSION_TYPES = get_args(ExpressionValue)
|
@@ -253,7 +253,7 @@ def do_subscript(value: Any, index: Any) -> Any:
|
|
253
253
|
and not is_constant_subscript(index)
|
254
254
|
and _is_qmod_value(index)
|
255
255
|
):
|
256
|
-
return AnyClassicalValue(
|
256
|
+
return AnyClassicalValue(qmod_val_to_expr_str(value))[index]
|
257
257
|
return value[index]
|
258
258
|
if index.is_signed or index.fraction_digits > 0:
|
259
259
|
raise ClassiqExpansionError(
|
@@ -270,7 +270,9 @@ def do_subscript(value: Any, index: Any) -> Any:
|
|
270
270
|
f"{index.size} qubits but the list size is {length} != 2**{index.size}"
|
271
271
|
)
|
272
272
|
if isinstance(value, ClassicalArrayProxy):
|
273
|
-
return AnyClassicalValue(
|
273
|
+
return AnyClassicalValue(
|
274
|
+
f"do_subscript({qmod_val_to_expr_str(value)}, {qmod_val_to_expr_str(index)})"
|
275
|
+
)
|
274
276
|
else:
|
275
277
|
return Piecewise(
|
276
278
|
*[(item, Eq(index, idx)) for idx, item in enumerate(value[:-1])],
|
@@ -286,9 +288,29 @@ def do_slice(value: Any, lower: Any, upper: Any) -> Any:
|
|
286
288
|
return do_subscript(value, slice(lower, upper))
|
287
289
|
|
288
290
|
|
291
|
+
def do_sum(val: Any) -> Any:
|
292
|
+
if isinstance(val, AnyClassicalValue):
|
293
|
+
return AnyClassicalValue(f"sum({val})")
|
294
|
+
return sum(val)
|
295
|
+
|
296
|
+
|
297
|
+
do_sum.__name__ = "sum"
|
298
|
+
|
299
|
+
|
300
|
+
def mod_inverse(a: Any, b: Any) -> Any:
|
301
|
+
if (
|
302
|
+
isinstance(a, AnyClassicalValue)
|
303
|
+
or (isinstance(a, sympy.Basic) and len(a.free_symbols) > 0)
|
304
|
+
or isinstance(b, AnyClassicalValue)
|
305
|
+
or (isinstance(b, sympy.Basic) and len(b.free_symbols) > 0)
|
306
|
+
):
|
307
|
+
return AnyClassicalValue(f"mod_inverse({a}, {b})")
|
308
|
+
return sympy.mod_inverse(a, b)
|
309
|
+
|
310
|
+
|
289
311
|
CORE_LIB_FUNCTIONS_LIST: list[Callable] = [
|
290
312
|
print,
|
291
|
-
|
313
|
+
do_sum,
|
292
314
|
struct_literal,
|
293
315
|
get_field,
|
294
316
|
get_type,
|
@@ -300,8 +322,29 @@ CORE_LIB_FUNCTIONS_LIST: list[Callable] = [
|
|
300
322
|
BitwiseNot,
|
301
323
|
BitwiseOr,
|
302
324
|
LogicalXor,
|
325
|
+
RShift,
|
326
|
+
LShift,
|
327
|
+
mod_inverse,
|
328
|
+
]
|
329
|
+
|
330
|
+
|
331
|
+
def _symbolic_function(func: str) -> Callable:
|
332
|
+
def wrapper(*args: Any) -> AnyClassicalValue:
|
333
|
+
return AnyClassicalValue(
|
334
|
+
f"{func}({', '.join(map(qmod_val_to_expr_str, args))})"
|
335
|
+
)
|
336
|
+
|
337
|
+
wrapper.__name__ = func
|
338
|
+
return wrapper
|
339
|
+
|
340
|
+
|
341
|
+
QMOD_CLASSICAL_FUNCTIONS = [
|
342
|
+
_symbolic_function(func) for func in qmod_classical_functions
|
303
343
|
]
|
304
344
|
|
305
345
|
ATOMIC_EXPRESSION_FUNCTIONS = {
|
306
|
-
**{
|
346
|
+
**{
|
347
|
+
core_func.__name__: core_func
|
348
|
+
for core_func in CORE_LIB_FUNCTIONS_LIST + QMOD_CLASSICAL_FUNCTIONS
|
349
|
+
},
|
307
350
|
}
|
@@ -15,6 +15,7 @@ from classiq.interface.generator.functions.classical_type import ClassicalType
|
|
15
15
|
from classiq.interface.generator.functions.port_declaration import (
|
16
16
|
PortDeclarationDirection,
|
17
17
|
)
|
18
|
+
from classiq.interface.generator.functions.type_qualifier import TypeQualifier
|
18
19
|
from classiq.interface.model.classical_parameter_declaration import (
|
19
20
|
ClassicalParameterDeclaration,
|
20
21
|
)
|
@@ -132,6 +133,7 @@ class _CapturedHandle(_Captured):
|
|
132
133
|
name=self.mangled_name,
|
133
134
|
quantum_type=self.quantum_type,
|
134
135
|
direction=self.direction.dump(),
|
136
|
+
type_qualifier=TypeQualifier.Inferred, # TODO https://classiq.atlassian.net/browse/CLS-1830
|
135
137
|
)
|
136
138
|
|
137
139
|
def is_same_var(self, other: "_CapturedHandle") -> bool:
|
@@ -17,6 +17,7 @@ from classiq.interface.generator.expressions.proxies.classical.classical_struct_
|
|
17
17
|
from classiq.interface.generator.expressions.proxies.classical.utils import (
|
18
18
|
get_proxy_type,
|
19
19
|
)
|
20
|
+
from classiq.interface.helpers.pydantic_model_helpers import nameables_to_dict
|
20
21
|
from classiq.interface.model.quantum_function_declaration import (
|
21
22
|
NamedParamsQuantumFunctionDeclaration,
|
22
23
|
PositionalArg,
|
@@ -43,6 +44,10 @@ class Closure:
|
|
43
44
|
positional_arg_declarations: Sequence[PositionalArg] = tuple()
|
44
45
|
captured_vars: CapturedVars = field(default_factory=CapturedVars)
|
45
46
|
|
47
|
+
@property
|
48
|
+
def parameters_dict(self) -> dict[str, PositionalArg]:
|
49
|
+
return nameables_to_dict(self.positional_arg_declarations)
|
50
|
+
|
46
51
|
|
47
52
|
@dataclass(frozen=True)
|
48
53
|
class GenerativeClosure(Closure):
|
@@ -1,6 +1,9 @@
|
|
1
1
|
from typing import Any, Union
|
2
2
|
|
3
3
|
from classiq.interface.exceptions import ClassiqExpansionError
|
4
|
+
from classiq.interface.generator.expressions.proxies.classical.any_classical_value import (
|
5
|
+
AnyClassicalValue,
|
6
|
+
)
|
4
7
|
from classiq.interface.generator.expressions.proxies.classical.classical_array_proxy import (
|
5
8
|
ClassicalArrayProxy,
|
6
9
|
)
|
@@ -17,6 +20,7 @@ from classiq.interface.generator.functions.classical_type import (
|
|
17
20
|
)
|
18
21
|
from classiq.interface.generator.functions.type_name import TypeName
|
19
22
|
from classiq.interface.generator.types.struct_declaration import StructDeclaration
|
23
|
+
from classiq.interface.helpers.backward_compatibility import zip_strict
|
20
24
|
|
21
25
|
|
22
26
|
def infer_classical_type(val: Any, classical_type: ClassicalType) -> ClassicalType:
|
@@ -33,7 +37,7 @@ def _infer_classical_struct_type(val: Any, classical_type: TypeName) -> Classica
|
|
33
37
|
decl = val.struct_declaration
|
34
38
|
new_fields = {
|
35
39
|
field_name: infer_classical_type(field_val, field_type)
|
36
|
-
for (field_name, field_val), field_type in
|
40
|
+
for (field_name, field_val), field_type in zip_strict(
|
37
41
|
val.fields.items(),
|
38
42
|
decl.variables.values(),
|
39
43
|
strict=True,
|
@@ -49,13 +53,20 @@ def _infer_classical_struct_type(val: Any, classical_type: TypeName) -> Classica
|
|
49
53
|
def _infer_classical_array_type(
|
50
54
|
val: Any, classical_type: Union[ClassicalArray, ClassicalList]
|
51
55
|
) -> ClassicalType:
|
52
|
-
if isinstance(val,
|
53
|
-
val_length = len(val)
|
54
|
-
elif isinstance(val, ClassicalArrayProxy):
|
56
|
+
if isinstance(val, ClassicalArrayProxy):
|
55
57
|
val_length = val.length
|
58
|
+
elif isinstance(val, list):
|
59
|
+
val_length = len(val)
|
60
|
+
elif isinstance(val, AnyClassicalValue):
|
61
|
+
return classical_type
|
56
62
|
else:
|
57
63
|
raise ClassiqExpansionError(f"Array expected, got {str(val)!r}")
|
58
|
-
if
|
64
|
+
if (
|
65
|
+
isinstance(classical_type, ClassicalArray)
|
66
|
+
and isinstance(val_length, int)
|
67
|
+
and isinstance(classical_type.size, int)
|
68
|
+
and val_length != classical_type.size
|
69
|
+
):
|
59
70
|
raise ClassiqExpansionError(
|
60
71
|
f"Type mismatch: Argument has {val_length} items but "
|
61
72
|
f"{classical_type.size} expected"
|
@@ -63,7 +74,7 @@ def _infer_classical_array_type(
|
|
63
74
|
return ClassicalArray(
|
64
75
|
element_type=(
|
65
76
|
infer_classical_type(val[0], classical_type.element_type)
|
66
|
-
if val_length > 0
|
77
|
+
if not isinstance(val_length, int) or val_length > 0
|
67
78
|
else classical_type.element_type
|
68
79
|
),
|
69
80
|
size=val_length,
|
@@ -1,10 +1,15 @@
|
|
1
|
-
from typing import TypeVar, Union
|
1
|
+
from typing import Optional, TypeVar, Union
|
2
|
+
|
3
|
+
import sympy
|
2
4
|
|
3
5
|
from classiq.interface.exceptions import (
|
4
6
|
ClassiqExpansionError,
|
5
7
|
ClassiqInternalExpansionError,
|
6
8
|
)
|
7
9
|
from classiq.interface.generator.expressions.expression import Expression
|
10
|
+
from classiq.interface.generator.expressions.proxies.classical.any_classical_value import (
|
11
|
+
AnyClassicalValue,
|
12
|
+
)
|
8
13
|
from classiq.interface.generator.functions.concrete_types import ConcreteQuantumType
|
9
14
|
from classiq.interface.generator.functions.port_declaration import (
|
10
15
|
PortDeclarationDirection,
|
@@ -178,7 +183,8 @@ def _evaluate_qarray_in_quantum_symbol(
|
|
178
183
|
"length",
|
179
184
|
param_name,
|
180
185
|
)
|
181
|
-
|
186
|
+
if new_length is not None:
|
187
|
+
set_length(type_to_update, new_length)
|
182
188
|
return type_to_update
|
183
189
|
|
184
190
|
|
@@ -194,7 +200,8 @@ def _evaluate_qnum_in_quantum_symbol(
|
|
194
200
|
"sign",
|
195
201
|
param_name,
|
196
202
|
)
|
197
|
-
|
203
|
+
if new_is_sign is not None:
|
204
|
+
type_to_update.is_signed = Expression(expr=str(new_is_sign))
|
198
205
|
if type_to_update.fraction_digits is not None:
|
199
206
|
new_fraction_digits = _eval_expr(
|
200
207
|
type_to_update.fraction_digits,
|
@@ -204,7 +211,8 @@ def _evaluate_qnum_in_quantum_symbol(
|
|
204
211
|
"fraction digits",
|
205
212
|
param_name,
|
206
213
|
)
|
207
|
-
|
214
|
+
if new_fraction_digits is not None:
|
215
|
+
type_to_update.fraction_digits = Expression(expr=str(new_fraction_digits))
|
208
216
|
if type_to_update.size is not None:
|
209
217
|
new_size = _eval_expr(
|
210
218
|
type_to_update.size,
|
@@ -214,7 +222,8 @@ def _evaluate_qnum_in_quantum_symbol(
|
|
214
222
|
"size",
|
215
223
|
param_name,
|
216
224
|
)
|
217
|
-
|
225
|
+
if new_size is not None:
|
226
|
+
set_size(type_to_update, new_size, param_name)
|
218
227
|
return type_to_update
|
219
228
|
|
220
229
|
|
@@ -228,17 +237,21 @@ def _eval_expr(
|
|
228
237
|
type_name: str,
|
229
238
|
attr_name: str,
|
230
239
|
param_name: str,
|
231
|
-
) -> _EXPR_TYPE:
|
240
|
+
) -> Optional[_EXPR_TYPE]:
|
232
241
|
val = evaluate_classical_expression(expression, scope).value
|
233
242
|
if expected_type is int and isinstance(val, float):
|
234
243
|
val = int(val)
|
235
|
-
if
|
236
|
-
|
237
|
-
|
238
|
-
|
239
|
-
|
240
|
-
|
241
|
-
|
244
|
+
if isinstance(val, expected_type):
|
245
|
+
return val
|
246
|
+
if isinstance(val, AnyClassicalValue) or (
|
247
|
+
isinstance(val, sympy.Basic) and len(val.free_symbols) > 0
|
248
|
+
):
|
249
|
+
return None
|
250
|
+
raise ClassiqExpansionError(
|
251
|
+
f"When inferring the type of parameter {param_name!r}: "
|
252
|
+
f"{type_name} {attr_name} must be {expected_type.__name__}, got "
|
253
|
+
f"{str(val)!r}"
|
254
|
+
)
|
242
255
|
|
243
256
|
|
244
257
|
def _evaluate_qstruct_in_quantum_symbol(
|
@@ -73,7 +73,7 @@ def evaluate(
|
|
73
73
|
try:
|
74
74
|
sympify_result = sympify(sympy_expr, locals=model_locals)
|
75
75
|
except (TypeError, IndexError) as e:
|
76
|
-
raise ClassiqExpansionError(str(e)) from
|
76
|
+
raise ClassiqExpansionError(str(e)) from e
|
77
77
|
except AttributeError as e:
|
78
78
|
if isinstance(e.obj, EnumMeta):
|
79
79
|
raise ClassiqExpansionError(
|
@@ -16,7 +16,7 @@ from classiq.interface.generator.expressions.proxies.classical.utils import (
|
|
16
16
|
get_proxy_type,
|
17
17
|
)
|
18
18
|
from classiq.interface.generator.functions.type_name import Struct
|
19
|
-
from classiq.interface.helpers.datastructures import
|
19
|
+
from classiq.interface.helpers.datastructures import LenList
|
20
20
|
from classiq.interface.helpers.pydantic_model_helpers import nameables_to_dict
|
21
21
|
from classiq.interface.model.native_function_definition import NativeFunctionDefinition
|
22
22
|
from classiq.interface.model.port_declaration import PortDeclaration
|
@@ -31,16 +31,18 @@ from classiq.model_expansions.closure import (
|
|
31
31
|
FunctionClosure,
|
32
32
|
GenerativeClosure,
|
33
33
|
)
|
34
|
-
from classiq.model_expansions.scope import Evaluated
|
34
|
+
from classiq.model_expansions.scope import Evaluated
|
35
35
|
from classiq.qmod.generative import generative_mode_context, set_frontend_interpreter
|
36
36
|
from classiq.qmod.model_state_container import QMODULE
|
37
37
|
from classiq.qmod.qmod_parameter import CParamStruct, create_param
|
38
|
-
from classiq.qmod.qmod_variable import _create_qvar_for_qtype
|
38
|
+
from classiq.qmod.qmod_variable import QScalar, _create_qvar_for_qtype
|
39
39
|
from classiq.qmod.quantum_expandable import (
|
40
40
|
QTerminalCallable,
|
41
41
|
)
|
42
42
|
from classiq.qmod.quantum_function import QFunc
|
43
43
|
from classiq.qmod.semantics.annotation.call_annotation import resolve_function_calls
|
44
|
+
from classiq.qmod.symbolic_expr import SymbolicExpr, SymbolicSubscriptAndField
|
45
|
+
from classiq.qmod.utilities import qmod_val_to_expr_str
|
44
46
|
|
45
47
|
if TYPE_CHECKING:
|
46
48
|
from classiq.model_expansions.interpreters.generative_interpreter import (
|
@@ -65,36 +67,61 @@ def _unwrap_traceback_frame(e: Exception) -> Exception:
|
|
65
67
|
return e.with_traceback(back_tb)
|
66
68
|
|
67
69
|
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
70
|
+
class SymbolicList(LenList):
|
71
|
+
def __getitem__(self, index: Any) -> Any:
|
72
|
+
if isinstance(index, (QScalar, SymbolicExpr)) or (
|
73
|
+
isinstance(index, slice)
|
74
|
+
and any(
|
75
|
+
isinstance(slice_part, (QScalar, SymbolicExpr))
|
76
|
+
for slice_part in (index.start, index.stop, index.step)
|
77
|
+
)
|
78
|
+
):
|
79
|
+
return SymbolicSubscriptAndField(
|
80
|
+
qmod_val_to_expr_str(self), is_quantum=False
|
81
|
+
)[index]
|
82
|
+
try:
|
83
|
+
return super().__getitem__(index)
|
84
|
+
except (IndexError, TypeError) as e:
|
85
|
+
raise _unwrap_traceback_frame(e) from None
|
86
|
+
|
87
|
+
|
88
|
+
def translate_classical_ast_arg_to_python_qmod(value: Any) -> Any:
|
89
|
+
if isinstance(value, QmodStructInstance):
|
90
|
+
return QmodStructInstance(
|
91
|
+
value.struct_declaration,
|
92
|
+
{
|
93
|
+
field_name: translate_classical_ast_arg_to_python_qmod(field_value)
|
94
|
+
for field_name, field_value in value.fields.items()
|
95
|
+
},
|
73
96
|
)
|
97
|
+
if isinstance(value, list):
|
98
|
+
return SymbolicList(
|
99
|
+
[translate_classical_ast_arg_to_python_qmod(item) for item in value]
|
100
|
+
)
|
101
|
+
if isinstance(value, ClassicalProxy):
|
102
|
+
return create_param(str(value.handle), get_proxy_type(value), QMODULE)
|
103
|
+
|
104
|
+
return value
|
105
|
+
|
106
|
+
|
107
|
+
def translate_ast_arg_to_python_qmod(param: PositionalArg, value: Any) -> Any:
|
108
|
+
if isinstance(param, PortDeclaration):
|
109
|
+
return _create_qvar_for_qtype(value.quantum_type, value.handle)
|
74
110
|
if isinstance(param, QuantumOperandDeclaration):
|
75
111
|
if not param.is_list or not param.is_generative:
|
76
112
|
return QTerminalCallable(param)
|
77
113
|
inner_decl = param.model_copy(update={"is_list": False})
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
struct_type=Struct(name=classical_value.struct_declaration.name),
|
88
|
-
qmodule=QMODULE,
|
89
|
-
)
|
90
|
-
else:
|
91
|
-
return get_sdk_compatible_python_object(dict(classical_value.fields))
|
92
|
-
if isinstance(classical_value, ClassicalProxy):
|
93
|
-
return create_param(
|
94
|
-
str(classical_value.handle), get_proxy_type(classical_value), QMODULE
|
114
|
+
return [QTerminalCallable(inner_decl, index_=idx) for idx in range(len(value))]
|
115
|
+
if (
|
116
|
+
isinstance(value, QmodStructInstance)
|
117
|
+
and param.classical_type.is_purely_declarative
|
118
|
+
):
|
119
|
+
classical_type = Struct(name=value.struct_declaration.name)
|
120
|
+
classical_type.set_classical_struct_decl(value.struct_declaration)
|
121
|
+
return CParamStruct(
|
122
|
+
expr=param.name, struct_type=classical_type, qmodule=QMODULE
|
95
123
|
)
|
96
|
-
|
97
|
-
return get_sdk_compatible_python_object(classical_value)
|
124
|
+
return translate_classical_ast_arg_to_python_qmod(value)
|
98
125
|
|
99
126
|
|
100
127
|
class _InterpreterExpandable(QFunc):
|
@@ -140,14 +167,14 @@ class _InterpreterExpandable(QFunc):
|
|
140
167
|
name=name,
|
141
168
|
positional_arg_declarations=value.positional_arg_declarations,
|
142
169
|
)
|
143
|
-
|
144
|
-
|
145
|
-
|
146
|
-
|
147
|
-
):
|
170
|
+
continue
|
171
|
+
op_param = self._interpreter._builder.current_function.parameters_dict.get(
|
172
|
+
name
|
173
|
+
)
|
174
|
+
if isinstance(op_param, QuantumOperandDeclaration):
|
148
175
|
scope_func_decls[name] = QuantumFunctionDeclaration(
|
149
176
|
name=name,
|
150
|
-
positional_arg_declarations=
|
177
|
+
positional_arg_declarations=op_param.positional_arg_declarations,
|
151
178
|
)
|
152
179
|
return (
|
153
180
|
nameables_to_dict(self._interpreter._get_function_declarations())
|
@@ -161,7 +188,7 @@ def emit_generative_statements(
|
|
161
188
|
args: list[Evaluated],
|
162
189
|
) -> None:
|
163
190
|
python_qmod_args = [
|
164
|
-
translate_ast_arg_to_python_qmod(param, arg)
|
191
|
+
translate_ast_arg_to_python_qmod(param, arg.value)
|
165
192
|
for param, arg in zip(operation.positional_arg_declarations, args)
|
166
193
|
]
|
167
194
|
with _InterpreterExpandable(interpreter):
|
@@ -6,7 +6,6 @@ from contextlib import nullcontext
|
|
6
6
|
from functools import singledispatchmethod
|
7
7
|
from typing import Any, cast
|
8
8
|
|
9
|
-
import sympy
|
10
9
|
from pydantic import ValidationError
|
11
10
|
|
12
11
|
from classiq.interface.debug_info.debug_info import (
|
@@ -17,6 +16,9 @@ from classiq.interface.exceptions import (
|
|
17
16
|
ClassiqExpansionError,
|
18
17
|
ClassiqInternalExpansionError,
|
19
18
|
)
|
19
|
+
from classiq.interface.generator.expressions.atomic_expression_functions import (
|
20
|
+
CLASSICAL_ATTRIBUTES,
|
21
|
+
)
|
20
22
|
from classiq.interface.generator.expressions.expression import Expression
|
21
23
|
from classiq.interface.generator.types.compilation_metadata import CompilationMetadata
|
22
24
|
from classiq.interface.model.handle_binding import (
|
@@ -57,11 +59,13 @@ from classiq.model_expansions.scope_initialization import (
|
|
57
59
|
)
|
58
60
|
from classiq.model_expansions.utils.counted_name_allocator import CountedNameAllocator
|
59
61
|
from classiq.model_expansions.visitors.variable_references import VarRefCollector
|
62
|
+
from classiq.qmod.builtins.constants import __all__ as builtin_constants
|
60
63
|
from classiq.qmod.builtins.enums import BUILTIN_ENUM_DECLARATIONS
|
61
64
|
from classiq.qmod.builtins.structs import BUILTIN_STRUCT_DECLARATIONS
|
62
65
|
from classiq.qmod.model_state_container import QMODULE
|
63
66
|
from classiq.qmod.semantics.error_manager import ErrorManager
|
64
67
|
from classiq.qmod.semantics.validation.model_validation import validate_model
|
68
|
+
from classiq.qmod.utilities import qmod_val_to_expr_str
|
65
69
|
|
66
70
|
|
67
71
|
class BaseInterpreter:
|
@@ -126,7 +130,11 @@ class BaseInterpreter:
|
|
126
130
|
classical_execution_code=self._model.classical_execution_code,
|
127
131
|
execution_preferences=self._model.execution_preferences,
|
128
132
|
functions=list(self._expanded_functions.values()),
|
129
|
-
constants=
|
133
|
+
constants=[
|
134
|
+
const
|
135
|
+
for name, const in QMODULE.constants.items()
|
136
|
+
if name not in builtin_constants
|
137
|
+
],
|
130
138
|
enums=[
|
131
139
|
enum_decl
|
132
140
|
for name, enum_decl in QMODULE.enum_decls.items()
|
@@ -157,14 +165,17 @@ class BaseInterpreter:
|
|
157
165
|
@evaluate.register
|
158
166
|
def evaluate_classical_expression(self, expression: Expression) -> Evaluated:
|
159
167
|
expr = evaluate_classical_expression(expression, self._builder.current_scope)
|
160
|
-
if not isinstance(expr.value, sympy.Basic):
|
161
|
-
return expr
|
162
168
|
vrc = VarRefCollector(ignore_duplicated_handles=True, unevaluated=True)
|
163
|
-
vrc.visit(ast.parse(
|
169
|
+
vrc.visit(ast.parse(qmod_val_to_expr_str(expr.value)))
|
164
170
|
for handle in vrc.var_handles:
|
165
171
|
if handle.name in self._builder.current_scope and isinstance(
|
166
|
-
self._builder.current_scope[handle.name], QuantumSymbol
|
172
|
+
self._builder.current_scope[handle.name].value, QuantumSymbol
|
167
173
|
):
|
174
|
+
if (
|
175
|
+
isinstance(handle, FieldHandleBinding)
|
176
|
+
and handle.field in CLASSICAL_ATTRIBUTES
|
177
|
+
):
|
178
|
+
handle = handle.base_handle
|
168
179
|
self.evaluate(handle)
|
169
180
|
return expr
|
170
181
|
|
@@ -5,6 +5,7 @@ from pydantic import ValidationError
|
|
5
5
|
|
6
6
|
from classiq.interface.exceptions import ClassiqError
|
7
7
|
from classiq.interface.model.allocate import Allocate
|
8
|
+
from classiq.interface.model.bind_operation import BindOperation
|
8
9
|
from classiq.interface.model.native_function_definition import NativeFunctionDefinition
|
9
10
|
from classiq.interface.model.quantum_function_call import QuantumFunctionCall
|
10
11
|
from classiq.interface.model.quantum_function_declaration import (
|
@@ -16,6 +17,7 @@ from classiq.model_expansions.closure import FunctionClosure, GenerativeFunction
|
|
16
17
|
from classiq.model_expansions.interpreters.generative_interpreter import (
|
17
18
|
GenerativeInterpreter,
|
18
19
|
)
|
20
|
+
from classiq.model_expansions.quantum_operations import BindEmitter
|
19
21
|
from classiq.model_expansions.quantum_operations.allocate import AllocateEmitter
|
20
22
|
from classiq.model_expansions.quantum_operations.quantum_function_call import (
|
21
23
|
DeclarativeQuantumFunctionCallEmitter,
|
@@ -40,6 +42,9 @@ class FrontendGenerativeInterpreter(GenerativeInterpreter):
|
|
40
42
|
def emit_allocate(self, allocate: Allocate) -> None:
|
41
43
|
AllocateEmitter(self, allow_symbolic_size=True).emit(allocate)
|
42
44
|
|
45
|
+
def emit_bind(self, bind: BindOperation) -> None:
|
46
|
+
BindEmitter(self, allow_symbolic_size=True).emit(bind)
|
47
|
+
|
43
48
|
def emit_quantum_function_call(self, call: QuantumFunctionCall) -> None:
|
44
49
|
DeclarativeQuantumFunctionCallEmitter(self).emit(call)
|
45
50
|
|
@@ -61,7 +61,11 @@ from classiq.model_expansions.quantum_operations.allocate import AllocateEmitter
|
|
61
61
|
from classiq.model_expansions.quantum_operations.assignment_result_processor import (
|
62
62
|
AssignmentResultProcessor,
|
63
63
|
)
|
64
|
-
from classiq.model_expansions.quantum_operations.block_evaluator import
|
64
|
+
from classiq.model_expansions.quantum_operations.block_evaluator import (
|
65
|
+
BlockEvaluator,
|
66
|
+
IfElimination,
|
67
|
+
RepeatElimination,
|
68
|
+
)
|
65
69
|
from classiq.model_expansions.quantum_operations.composite_emitter import (
|
66
70
|
CompositeEmitter,
|
67
71
|
)
|
@@ -152,10 +156,16 @@ class GenerativeInterpreter(BaseInterpreter):
|
|
152
156
|
QuantumFunctionCallEmitter(self).emit(call)
|
153
157
|
|
154
158
|
@emit.register
|
159
|
+
def _emit_allocate(self, allocate: Allocate) -> None:
|
160
|
+
return self.emit_allocate(allocate)
|
161
|
+
|
155
162
|
def emit_allocate(self, allocate: Allocate) -> None:
|
156
163
|
AllocateEmitter(self).emit(allocate)
|
157
164
|
|
158
165
|
@emit.register
|
166
|
+
def _emit_bind(self, bind: BindOperation) -> None:
|
167
|
+
self.emit_bind(bind)
|
168
|
+
|
159
169
|
def emit_bind(self, bind: BindOperation) -> None:
|
160
170
|
BindEmitter(self).emit(bind)
|
161
171
|
|
@@ -210,6 +220,7 @@ class GenerativeInterpreter(BaseInterpreter):
|
|
210
220
|
self,
|
211
221
|
[
|
212
222
|
ExpressionEvaluator(self, "condition"),
|
223
|
+
IfElimination(self),
|
213
224
|
BlockEvaluator(
|
214
225
|
self,
|
215
226
|
CLASSICAL_IF_OPERATOR_NAME,
|
@@ -243,6 +254,7 @@ class GenerativeInterpreter(BaseInterpreter):
|
|
243
254
|
self,
|
244
255
|
[
|
245
256
|
ExpressionEvaluator(self, "count"),
|
257
|
+
RepeatElimination(self),
|
246
258
|
RepeatBlockEvaluator(self, REPEAT_OPERATOR_NAME, "body"),
|
247
259
|
],
|
248
260
|
).emit(repeat)
|