classiq 0.90.0__py3-none-any.whl → 0.91.1__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/evaluators/expression_evaluator.py +24 -124
- classiq/evaluators/qmod_expression_visitors/qmod_expression_simplifier.py +10 -3
- classiq/evaluators/qmod_node_evaluators/utils.py +0 -8
- classiq/interface/_version.py +1 -1
- classiq/interface/executor/result.py +22 -3
- classiq/interface/generator/expressions/expression_types.py +2 -0
- classiq/interface/generator/expressions/proxies/classical/classical_array_proxy.py +3 -8
- classiq/interface/generator/functions/classical_type.py +2 -5
- classiq/interface/generator/functions/type_name.py +0 -12
- classiq/interface/model/quantum_type.py +0 -39
- classiq/model_expansions/capturing/captured_vars.py +3 -0
- classiq/model_expansions/function_builder.py +18 -2
- classiq/model_expansions/interpreters/frontend_generative_interpreter.py +0 -10
- classiq/model_expansions/interpreters/generative_interpreter.py +63 -18
- classiq/model_expansions/quantum_operations/emitter.py +13 -3
- classiq/model_expansions/quantum_operations/expression_evaluator.py +49 -5
- classiq/model_expansions/scope.py +5 -14
- classiq/model_expansions/utils/handles_collector.py +7 -0
- classiq/qmod/builtins/operations.py +7 -3
- classiq/qmod/qmod_variable.py +3 -4
- classiq/qmod/semantics/error_manager.py +34 -15
- classiq/qmod/symbolic.py +15 -4
- classiq/qmod/utilities.py +4 -1
- classiq/synthesis.py +1 -2
- {classiq-0.90.0.dist-info → classiq-0.91.1.dist-info}/METADATA +1 -1
- {classiq-0.90.0.dist-info → classiq-0.91.1.dist-info}/RECORD +27 -41
- 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 -395
- 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 -136
- classiq/model_expansions/utils/sympy_utils.py +0 -24
- {classiq-0.90.0.dist-info → classiq-0.91.1.dist-info}/WHEEL +0 -0
|
@@ -1,38 +1,34 @@
|
|
|
1
|
-
import
|
|
2
|
-
from collections.abc import Mapping
|
|
3
|
-
from enum import EnumMeta
|
|
1
|
+
from enum import Enum
|
|
4
2
|
from typing import Any
|
|
5
3
|
|
|
6
|
-
|
|
4
|
+
import sympy
|
|
7
5
|
|
|
8
|
-
from classiq.interface.exceptions import
|
|
6
|
+
from classiq.interface.exceptions import ClassiqInternalExpansionError
|
|
9
7
|
from classiq.interface.generator.constant import Constant
|
|
10
|
-
from classiq.interface.generator.expressions.
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
from classiq.interface.generator.expressions.expression import Expression
|
|
14
|
-
from classiq.interface.generator.expressions.expression_types import ExpressionValue
|
|
15
|
-
from classiq.interface.generator.expressions.non_symbolic_expr import NonSymbolicExpr
|
|
16
|
-
from classiq.interface.generator.expressions.proxies.quantum.qmod_sized_proxy import (
|
|
17
|
-
QmodSizedProxy,
|
|
18
|
-
)
|
|
19
|
-
from classiq.interface.generator.expressions.sympy_supported_expressions import (
|
|
20
|
-
SYMPY_SUPPORTED_EXPRESSIONS,
|
|
8
|
+
from classiq.interface.generator.expressions.expression_types import RuntimeConstant
|
|
9
|
+
from classiq.interface.generator.expressions.proxies.classical.qmod_struct_instance import (
|
|
10
|
+
QmodStructInstance,
|
|
21
11
|
)
|
|
22
12
|
|
|
23
13
|
from classiq.evaluators.classical_expression import evaluate_classical_expression
|
|
24
|
-
from classiq.model_expansions.atomic_expression_functions_defs import (
|
|
25
|
-
ATOMIC_EXPRESSION_FUNCTIONS,
|
|
26
|
-
qmod_val_to_python,
|
|
27
|
-
)
|
|
28
14
|
from classiq.model_expansions.scope import Evaluated, Scope
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
)
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
def qmod_val_to_python(val: RuntimeConstant) -> Any:
|
|
18
|
+
if isinstance(val, (int, float, bool, complex, Enum)):
|
|
19
|
+
return val
|
|
20
|
+
if isinstance(val, list):
|
|
21
|
+
return [qmod_val_to_python(item) for item in val]
|
|
22
|
+
if isinstance(val, QmodStructInstance):
|
|
23
|
+
return {
|
|
24
|
+
field_name: qmod_val_to_python(field_val)
|
|
25
|
+
for field_name, field_val in val.fields.items()
|
|
26
|
+
}
|
|
27
|
+
if isinstance(val, sympy.Expr):
|
|
28
|
+
return val.evalf()
|
|
29
|
+
raise ClassiqInternalExpansionError(
|
|
30
|
+
f"Could not convert Qmod value {str(val)!r} of type {type(val).__name__} to Python"
|
|
31
|
+
)
|
|
36
32
|
|
|
37
33
|
|
|
38
34
|
def evaluate_constants(constants: list[Constant]) -> Scope:
|
|
@@ -47,102 +43,6 @@ def evaluate_constants(constants: list[Constant]) -> Scope:
|
|
|
47
43
|
def evaluate_constants_as_python(constants: list[Constant]) -> dict[str, Any]:
|
|
48
44
|
evaluated = evaluate_constants(constants)
|
|
49
45
|
return {
|
|
50
|
-
constant.name: qmod_val_to_python(
|
|
51
|
-
evaluated[constant.name].value, constant.const_type
|
|
52
|
-
)
|
|
46
|
+
constant.name: qmod_val_to_python(evaluated[constant.name].value)
|
|
53
47
|
for constant in constants
|
|
54
48
|
}
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
def _quick_eval(expr: str) -> Any:
|
|
58
|
-
try:
|
|
59
|
-
return int(expr)
|
|
60
|
-
except ValueError:
|
|
61
|
-
pass
|
|
62
|
-
try:
|
|
63
|
-
return float(expr)
|
|
64
|
-
except ValueError:
|
|
65
|
-
pass
|
|
66
|
-
return None
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
def evaluate(
|
|
70
|
-
expr: Expression, locals_dict: Mapping[str, EvaluatedExpression]
|
|
71
|
-
) -> EvaluatedExpression:
|
|
72
|
-
val = _quick_eval(expr.expr)
|
|
73
|
-
if val is not None:
|
|
74
|
-
return EvaluatedExpression(value=val)
|
|
75
|
-
|
|
76
|
-
model_locals: dict[str, Any] = {}
|
|
77
|
-
model_locals.update(ATOMIC_EXPRESSION_FUNCTIONS)
|
|
78
|
-
model_locals.update(
|
|
79
|
-
{
|
|
80
|
-
enum_decl.name: enum_decl.create_enum()
|
|
81
|
-
for enum_decl in (QMODULE.enum_decls | BUILTIN_ENUM_DECLARATIONS).values()
|
|
82
|
-
}
|
|
83
|
-
)
|
|
84
|
-
# locals override builtin-functions
|
|
85
|
-
model_locals.update({name: expr.value for name, expr in locals_dict.items()})
|
|
86
|
-
|
|
87
|
-
_validate_undefined_vars(expr.expr, model_locals)
|
|
88
|
-
|
|
89
|
-
sympy_expr = translate_to_sympy(expr.expr)
|
|
90
|
-
try:
|
|
91
|
-
sympify_result = sympify(sympy_expr, locals=model_locals)
|
|
92
|
-
except (TypeError, IndexError) as e:
|
|
93
|
-
raise ClassiqExpansionError(str(e)) from e
|
|
94
|
-
except AttributeError as e:
|
|
95
|
-
if isinstance(e.obj, EnumMeta):
|
|
96
|
-
raise ClassiqExpansionError(
|
|
97
|
-
f"Enum {e.obj.__name__} has no member {e.name!r}. Available members: "
|
|
98
|
-
f"{', '.join(e.obj.__members__)}"
|
|
99
|
-
) from e
|
|
100
|
-
raise
|
|
101
|
-
except SympifyError as e:
|
|
102
|
-
expr = e.expr
|
|
103
|
-
if isinstance(expr, QmodSizedProxy) and isinstance(expr, NonSymbolicExpr):
|
|
104
|
-
raise ClassiqExpansionError(
|
|
105
|
-
f"{expr.type_name} {str(expr)!r} does not support arithmetic operations"
|
|
106
|
-
) from e
|
|
107
|
-
raise
|
|
108
|
-
|
|
109
|
-
return EvaluatedExpression(
|
|
110
|
-
value=sympy_to_python(sympify_result, locals=model_locals)
|
|
111
|
-
)
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
def _validate_undefined_vars(
|
|
115
|
-
expr: str, model_locals: dict[str, ExpressionValue]
|
|
116
|
-
) -> None:
|
|
117
|
-
id_visitor = _VarsCollector()
|
|
118
|
-
id_visitor.visit(ast.parse(expr))
|
|
119
|
-
identifiers = id_visitor.vars
|
|
120
|
-
undefined_vars = (
|
|
121
|
-
identifiers
|
|
122
|
-
- model_locals.keys()
|
|
123
|
-
- set(SYMPY_SUPPORTED_EXPRESSIONS)
|
|
124
|
-
- set(symbolic.__all__)
|
|
125
|
-
)
|
|
126
|
-
|
|
127
|
-
if len(undefined_vars) == 1:
|
|
128
|
-
undefined_var = undefined_vars.__iter__().__next__()
|
|
129
|
-
raise ClassiqExpansionError(f"Variable {undefined_var!r} is undefined")
|
|
130
|
-
elif len(undefined_vars) > 1:
|
|
131
|
-
raise ClassiqExpansionError(f"Variables {list(undefined_vars)} are undefined")
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
class _VarsCollector(ast.NodeTransformer):
|
|
135
|
-
def __init__(self) -> None:
|
|
136
|
-
self.vars: set[str] = set()
|
|
137
|
-
|
|
138
|
-
def visit_Name(self, node: ast.Name) -> None:
|
|
139
|
-
self.vars.add(node.id)
|
|
140
|
-
|
|
141
|
-
def visit_Call(self, node: ast.Call) -> None:
|
|
142
|
-
func = node.func
|
|
143
|
-
self.visit(func)
|
|
144
|
-
if not isinstance(func, ast.Name) or func.id != "struct_literal":
|
|
145
|
-
for arg in node.args:
|
|
146
|
-
self.visit(arg)
|
|
147
|
-
for kw in node.keywords:
|
|
148
|
-
self.visit(kw)
|
|
@@ -23,7 +23,14 @@ from classiq.evaluators.qmod_expression_visitors.sympy_wrappers import (
|
|
|
23
23
|
LShift,
|
|
24
24
|
RShift,
|
|
25
25
|
)
|
|
26
|
-
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
def _div_wrapper(lhs: Any, rhs: Any) -> Any:
|
|
29
|
+
res = lhs / rhs
|
|
30
|
+
if isinstance(res, sympy.Expr):
|
|
31
|
+
res = res.evalf()
|
|
32
|
+
return res
|
|
33
|
+
|
|
27
34
|
|
|
28
35
|
_SYMPY_WRAPPERS = {
|
|
29
36
|
wrapper.__name__: wrapper
|
|
@@ -36,7 +43,7 @@ _SYMPY_WRAPPERS = {
|
|
|
36
43
|
RShift,
|
|
37
44
|
]
|
|
38
45
|
} | {
|
|
39
|
-
|
|
46
|
+
_div_wrapper.__name__: _div_wrapper,
|
|
40
47
|
}
|
|
41
48
|
|
|
42
49
|
_PY_NODE = TypeVar("_PY_NODE", bound=ast.AST)
|
|
@@ -172,7 +179,7 @@ class _SympyCompatibilityTransformer(OutOfPlaceNodeTransformer):
|
|
|
172
179
|
sympy_func = BitwiseAnd.__name__
|
|
173
180
|
elif isinstance(node.op, ast.Div):
|
|
174
181
|
return ast.Call(
|
|
175
|
-
func=ast.Name(id=
|
|
182
|
+
func=ast.Name(id=_div_wrapper.__name__),
|
|
176
183
|
args=[node.left, node.right],
|
|
177
184
|
keywords=[],
|
|
178
185
|
)
|
|
@@ -65,14 +65,6 @@ def get_numeric_properties(
|
|
|
65
65
|
return size, is_signed, fraction_digits
|
|
66
66
|
|
|
67
67
|
|
|
68
|
-
def qnum_is_qint(qmod_type: QuantumType) -> bool:
|
|
69
|
-
return isinstance(qmod_type, QuantumBit) or (
|
|
70
|
-
isinstance(qmod_type, QuantumNumeric)
|
|
71
|
-
and (not qmod_type.has_sign or not qmod_type.sign_value)
|
|
72
|
-
and (not qmod_type.has_fraction_digits or qmod_type.fraction_digits_value == 0)
|
|
73
|
-
)
|
|
74
|
-
|
|
75
|
-
|
|
76
68
|
def element_types(
|
|
77
69
|
classical_type: Union[ClassicalArray, ClassicalTuple],
|
|
78
70
|
) -> list[ClassicalType]:
|
classiq/interface/_version.py
CHANGED
|
@@ -1,4 +1,6 @@
|
|
|
1
|
+
import cmath
|
|
1
2
|
import functools
|
|
3
|
+
import math
|
|
2
4
|
import operator
|
|
3
5
|
from collections import defaultdict
|
|
4
6
|
from collections.abc import Iterator, Mapping
|
|
@@ -46,6 +48,8 @@ BITSTRING = "bitstring"
|
|
|
46
48
|
PROBABILITY = "probability"
|
|
47
49
|
AMPLITUDE = "amplitude"
|
|
48
50
|
COUNT = "count"
|
|
51
|
+
MAGNITUDE = "magnitude"
|
|
52
|
+
PHASE = "phase"
|
|
49
53
|
|
|
50
54
|
if TYPE_CHECKING:
|
|
51
55
|
DotAccessParsedState = Mapping[Name, Any]
|
|
@@ -191,6 +195,14 @@ def _flatten_columns(df: pd.DataFrame, columns_to_flatten: list[str]) -> pd.Data
|
|
|
191
195
|
return final_df[valid_final_columns]
|
|
192
196
|
|
|
193
197
|
|
|
198
|
+
def _pretty_magnitude_phase_from_amplitude(amplitude: complex) -> tuple[str, str]:
|
|
199
|
+
magnitude_str = f"{abs(amplitude):.2f}"
|
|
200
|
+
phase = cmath.phase(amplitude) / math.pi
|
|
201
|
+
phase_str = f"{phase:.2f}π"
|
|
202
|
+
|
|
203
|
+
return magnitude_str, phase_str
|
|
204
|
+
|
|
205
|
+
|
|
194
206
|
class ExecutionDetails(BaseModel, QmodPyObject):
|
|
195
207
|
vendor_format_result: dict[str, Any] = pydantic.Field(
|
|
196
208
|
..., description="Result in proprietary vendor format"
|
|
@@ -377,11 +389,14 @@ class ExecutionDetails(BaseModel, QmodPyObject):
|
|
|
377
389
|
for bitstring, amplitude in self.state_vector.items():
|
|
378
390
|
data[BITSTRING].append(bitstring)
|
|
379
391
|
data[AMPLITUDE].append(amplitude)
|
|
392
|
+
magnitude, phase = _pretty_magnitude_phase_from_amplitude(amplitude)
|
|
393
|
+
data[MAGNITUDE].append(magnitude)
|
|
394
|
+
data[PHASE].append(phase)
|
|
380
395
|
data[PROBABILITY].append(abs(amplitude) ** 2)
|
|
381
396
|
for name, value in self.parsed_state_vector_states[bitstring].items():
|
|
382
397
|
data[name].append(value)
|
|
383
398
|
|
|
384
|
-
final_columns = [AMPLITUDE, PROBABILITY, BITSTRING]
|
|
399
|
+
final_columns = [AMPLITUDE, MAGNITUDE, PHASE, PROBABILITY, BITSTRING]
|
|
385
400
|
columns = [
|
|
386
401
|
col for col in data.keys() if col not in final_columns
|
|
387
402
|
] + final_columns
|
|
@@ -390,12 +405,16 @@ class ExecutionDetails(BaseModel, QmodPyObject):
|
|
|
390
405
|
|
|
391
406
|
@functools.cached_property
|
|
392
407
|
def dataframe(self) -> pd.DataFrame:
|
|
393
|
-
reserved_words = frozenset(
|
|
408
|
+
reserved_words = frozenset(
|
|
409
|
+
[BITSTRING, PROBABILITY, COUNT, AMPLITUDE, PHASE, MAGNITUDE]
|
|
410
|
+
)
|
|
394
411
|
_invalid_output_names = reserved_words.intersection(
|
|
395
412
|
self.output_qubits_map.keys()
|
|
396
413
|
)
|
|
397
414
|
if _invalid_output_names:
|
|
398
|
-
raise ClassiqValueError(
|
|
415
|
+
raise ClassiqValueError(
|
|
416
|
+
f"The following names are reserved and cannot be used as outputs when constructing a dataframe: {_invalid_output_names}"
|
|
417
|
+
)
|
|
399
418
|
|
|
400
419
|
if self.state_vector:
|
|
401
420
|
df = self._state_vector_df()
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
from collections.abc import Mapping
|
|
2
|
-
from typing import TYPE_CHECKING, Any, Union
|
|
2
|
+
from typing import TYPE_CHECKING, Any, Optional, Union
|
|
3
3
|
|
|
4
4
|
import sympy
|
|
5
5
|
from sympy import Integer
|
|
@@ -8,9 +8,6 @@ from typing_extensions import TypeGuard
|
|
|
8
8
|
from classiq.interface.exceptions import ClassiqIndexError
|
|
9
9
|
from classiq.interface.generator.expressions.expression import Expression
|
|
10
10
|
from classiq.interface.generator.expressions.non_symbolic_expr import NonSymbolicExpr
|
|
11
|
-
from classiq.interface.generator.expressions.proxies.classical.any_classical_value import (
|
|
12
|
-
AnyClassicalValue,
|
|
13
|
-
)
|
|
14
11
|
from classiq.interface.generator.expressions.proxies.classical.classical_proxy import (
|
|
15
12
|
ClassicalProxy,
|
|
16
13
|
)
|
|
@@ -28,8 +25,6 @@ if TYPE_CHECKING:
|
|
|
28
25
|
|
|
29
26
|
|
|
30
27
|
def _is_int(val: Any) -> TypeGuard[Union[int, sympy.Basic]]:
|
|
31
|
-
if isinstance(val, AnyClassicalValue):
|
|
32
|
-
return False
|
|
33
28
|
if isinstance(val, sympy.Basic):
|
|
34
29
|
return val.is_Number
|
|
35
30
|
return isinstance(val, int)
|
|
@@ -99,7 +94,7 @@ class ClassicalArrayProxy(ClassicalSequenceProxy):
|
|
|
99
94
|
self,
|
|
100
95
|
handle: HandleBinding,
|
|
101
96
|
element_type: "ConcreteClassicalType",
|
|
102
|
-
length: "ExpressionValue",
|
|
97
|
+
length: Optional["ExpressionValue"],
|
|
103
98
|
) -> None:
|
|
104
99
|
super().__init__(handle)
|
|
105
100
|
self._element_type = element_type
|
|
@@ -108,7 +103,7 @@ class ClassicalArrayProxy(ClassicalSequenceProxy):
|
|
|
108
103
|
self._length = length
|
|
109
104
|
|
|
110
105
|
@property
|
|
111
|
-
def length(self) -> "ExpressionValue":
|
|
106
|
+
def length(self) -> Optional["ExpressionValue"]:
|
|
112
107
|
return self._length
|
|
113
108
|
|
|
114
109
|
def get_slice_at(self, start: Any, stop: Any) -> ClassicalProxy:
|
|
@@ -9,9 +9,6 @@ from classiq.interface.ast_node import HashableASTNode
|
|
|
9
9
|
from classiq.interface.exceptions import ClassiqInternalExpansionError
|
|
10
10
|
from classiq.interface.generator.expressions.expression import Expression
|
|
11
11
|
from classiq.interface.generator.expressions.expression_types import ExpressionValue
|
|
12
|
-
from classiq.interface.generator.expressions.proxies.classical.any_classical_value import (
|
|
13
|
-
AnyClassicalValue,
|
|
14
|
-
)
|
|
15
12
|
from classiq.interface.generator.expressions.proxies.classical.classical_array_proxy import (
|
|
16
13
|
ClassicalArrayProxy,
|
|
17
14
|
ClassicalTupleProxy,
|
|
@@ -163,9 +160,9 @@ class ClassicalArray(ClassicalType):
|
|
|
163
160
|
return self.length.to_int_value()
|
|
164
161
|
|
|
165
162
|
def get_classical_proxy(self, handle: HandleBinding) -> ClassicalProxy:
|
|
166
|
-
length: ExpressionValue
|
|
163
|
+
length: Optional[ExpressionValue]
|
|
167
164
|
if self.length is None:
|
|
168
|
-
length =
|
|
165
|
+
length = None
|
|
169
166
|
elif not self.length.is_evaluated():
|
|
170
167
|
raise ClassiqInternalExpansionError(
|
|
171
168
|
"Classical list length is not evaluated"
|
|
@@ -15,9 +15,6 @@ from classiq.interface.generator.expressions.proxies.classical.classical_scalar_
|
|
|
15
15
|
from classiq.interface.generator.expressions.proxies.classical.classical_struct_proxy import (
|
|
16
16
|
ClassicalStructProxy,
|
|
17
17
|
)
|
|
18
|
-
from classiq.interface.generator.expressions.proxies.quantum.qmod_qstruct_proxy import (
|
|
19
|
-
QmodQStructProxy,
|
|
20
|
-
)
|
|
21
18
|
from classiq.interface.generator.functions.classical_type import (
|
|
22
19
|
ClassicalType,
|
|
23
20
|
)
|
|
@@ -59,15 +56,6 @@ class TypeName(ClassicalType, QuantumType):
|
|
|
59
56
|
field_type.size_in_bits for field_type in fields_types
|
|
60
57
|
)
|
|
61
58
|
|
|
62
|
-
def get_proxy(self, handle: "HandleBinding") -> "QmodQStructProxy":
|
|
63
|
-
from classiq.interface.generator.expressions.proxies.quantum.qmod_qstruct_proxy import (
|
|
64
|
-
QmodQStructProxy,
|
|
65
|
-
)
|
|
66
|
-
|
|
67
|
-
return QmodQStructProxy(
|
|
68
|
-
handle=handle, struct_name=self.name, fields=self.fields
|
|
69
|
-
)
|
|
70
|
-
|
|
71
59
|
@property
|
|
72
60
|
def qmod_type_name(self) -> str:
|
|
73
61
|
return self.name
|
|
@@ -15,20 +15,8 @@ from classiq.interface.generator.arith.register_user_input import (
|
|
|
15
15
|
RegisterUserInput,
|
|
16
16
|
)
|
|
17
17
|
from classiq.interface.generator.expressions.expression import Expression
|
|
18
|
-
from classiq.interface.generator.expressions.proxies.quantum.qmod_qarray_proxy import (
|
|
19
|
-
QmodQArrayProxy,
|
|
20
|
-
)
|
|
21
|
-
from classiq.interface.generator.expressions.proxies.quantum.qmod_qscalar_proxy import (
|
|
22
|
-
QmodQBitProxy,
|
|
23
|
-
QmodQNumProxy,
|
|
24
|
-
QmodQScalarProxy,
|
|
25
|
-
)
|
|
26
|
-
from classiq.interface.generator.expressions.proxies.quantum.qmod_sized_proxy import (
|
|
27
|
-
QmodSizedProxy,
|
|
28
|
-
)
|
|
29
18
|
from classiq.interface.helpers.custom_pydantic_types import PydanticFloatTuple
|
|
30
19
|
from classiq.interface.helpers.pydantic_model_helpers import values_with_discriminator
|
|
31
|
-
from classiq.interface.model.handle_binding import HandleBinding
|
|
32
20
|
|
|
33
21
|
if TYPE_CHECKING:
|
|
34
22
|
from classiq.interface.generator.functions.concrete_types import ConcreteQuantumType
|
|
@@ -59,9 +47,6 @@ class QuantumType(HashableASTNode):
|
|
|
59
47
|
def minimal_size_in_bits(self) -> int:
|
|
60
48
|
raise NotImplementedError
|
|
61
49
|
|
|
62
|
-
def get_proxy(self, handle: "HandleBinding") -> QmodSizedProxy:
|
|
63
|
-
return QmodSizedProxy(handle=handle, size=self.size_in_bits)
|
|
64
|
-
|
|
65
50
|
@property
|
|
66
51
|
def qmod_type_name(self) -> str:
|
|
67
52
|
raise NotImplementedError
|
|
@@ -95,9 +80,6 @@ class QuantumType(HashableASTNode):
|
|
|
95
80
|
|
|
96
81
|
|
|
97
82
|
class QuantumScalar(QuantumType):
|
|
98
|
-
def get_proxy(self, handle: "HandleBinding") -> QmodQScalarProxy:
|
|
99
|
-
return QmodQScalarProxy(handle, size=self.size_in_bits)
|
|
100
|
-
|
|
101
83
|
@property
|
|
102
84
|
def has_sign(self) -> bool:
|
|
103
85
|
raise NotImplementedError
|
|
@@ -147,9 +129,6 @@ class QuantumBit(QuantumScalar):
|
|
|
147
129
|
def qmod_type_name(self) -> str:
|
|
148
130
|
return "QBit"
|
|
149
131
|
|
|
150
|
-
def get_proxy(self, handle: "HandleBinding") -> QmodQBitProxy:
|
|
151
|
-
return QmodQBitProxy(handle)
|
|
152
|
-
|
|
153
132
|
@property
|
|
154
133
|
def type_name(self) -> str:
|
|
155
134
|
return "Quantum bit"
|
|
@@ -233,16 +212,6 @@ class QuantumBitvector(QuantumType):
|
|
|
233
212
|
assert self.length is not None
|
|
234
213
|
return self.length.to_int_value()
|
|
235
214
|
|
|
236
|
-
def get_proxy(self, handle: "HandleBinding") -> QmodQArrayProxy:
|
|
237
|
-
element_size = self.element_type.size_in_bits
|
|
238
|
-
assert self.size_in_bits % element_size == 0
|
|
239
|
-
return QmodQArrayProxy(
|
|
240
|
-
handle,
|
|
241
|
-
self.element_type,
|
|
242
|
-
element_size,
|
|
243
|
-
self.size_in_bits // element_size,
|
|
244
|
-
)
|
|
245
|
-
|
|
246
215
|
@property
|
|
247
216
|
def qmod_type_name(self) -> str:
|
|
248
217
|
element_type = [self.element_type.qmod_type_name]
|
|
@@ -382,14 +351,6 @@ class QuantumNumeric(QuantumScalar):
|
|
|
382
351
|
):
|
|
383
352
|
self._size_in_bits = self.size.to_int_value()
|
|
384
353
|
|
|
385
|
-
def get_proxy(self, handle: "HandleBinding") -> QmodQNumProxy:
|
|
386
|
-
return QmodQNumProxy(
|
|
387
|
-
handle,
|
|
388
|
-
size=self.size_in_bits,
|
|
389
|
-
fraction_digits=self.fraction_digits_value,
|
|
390
|
-
is_signed=self.sign_value,
|
|
391
|
-
)
|
|
392
|
-
|
|
393
354
|
@property
|
|
394
355
|
def qmod_type_name(self) -> str:
|
|
395
356
|
if (
|
|
@@ -554,6 +554,9 @@ class CapturedVars:
|
|
|
554
554
|
],
|
|
555
555
|
)
|
|
556
556
|
|
|
557
|
+
def get_captured_classical_vars(self) -> list[str]:
|
|
558
|
+
return [var.name for var in self._captured_classical_vars]
|
|
559
|
+
|
|
557
560
|
def get_captured_parameters(self) -> list[PositionalArg]:
|
|
558
561
|
decls: list[PositionalArg]
|
|
559
562
|
decls = [
|
|
@@ -3,7 +3,10 @@ from contextlib import contextmanager
|
|
|
3
3
|
from dataclasses import dataclass, field
|
|
4
4
|
from typing import Generic, Optional, TypeVar
|
|
5
5
|
|
|
6
|
-
from classiq.interface.exceptions import
|
|
6
|
+
from classiq.interface.exceptions import (
|
|
7
|
+
ClassiqExpansionError,
|
|
8
|
+
ClassiqInternalExpansionError,
|
|
9
|
+
)
|
|
7
10
|
from classiq.interface.generator.compiler_keywords import (
|
|
8
11
|
EXPANDED_KEYWORD,
|
|
9
12
|
LAMBDA_KEYWORD,
|
|
@@ -31,7 +34,7 @@ from classiq.model_expansions.capturing.captured_vars import (
|
|
|
31
34
|
validate_end_state,
|
|
32
35
|
)
|
|
33
36
|
from classiq.model_expansions.closure import Closure, FunctionClosure
|
|
34
|
-
from classiq.model_expansions.scope import Scope
|
|
37
|
+
from classiq.model_expansions.scope import ClassicalSymbol, Scope
|
|
35
38
|
from classiq.model_expansions.utils.counted_name_allocator import CountedNameAllocator
|
|
36
39
|
|
|
37
40
|
ClosureType = TypeVar("ClosureType", bound=Closure)
|
|
@@ -190,6 +193,8 @@ class OperationBuilder:
|
|
|
190
193
|
self.current_function
|
|
191
194
|
).set_propagated()
|
|
192
195
|
validate_captured_directions(captured_vars)
|
|
196
|
+
else:
|
|
197
|
+
self._validate_no_captured_runtime_params(captured_vars)
|
|
193
198
|
if len(self._operations) < 2:
|
|
194
199
|
return
|
|
195
200
|
parent_block = self._operations[-2].blocks[self._blocks[-1]]
|
|
@@ -231,3 +236,14 @@ class OperationBuilder:
|
|
|
231
236
|
raise ClassiqInternalExpansionError("Could not allocate function name")
|
|
232
237
|
|
|
233
238
|
return name
|
|
239
|
+
|
|
240
|
+
def _validate_no_captured_runtime_params(self, captured_vars: CapturedVars) -> None:
|
|
241
|
+
if any(
|
|
242
|
+
var in self.current_scope
|
|
243
|
+
and isinstance(self.current_scope[var].value, ClassicalSymbol)
|
|
244
|
+
for var in captured_vars.get_captured_classical_vars()
|
|
245
|
+
):
|
|
246
|
+
raise ClassiqExpansionError(
|
|
247
|
+
"Runtime classical variables can only be declared and used at the "
|
|
248
|
+
"function's top scope"
|
|
249
|
+
)
|
|
@@ -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
|
|