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
@@ -66,8 +66,6 @@ class QuantumSymbol:
|
|
66
66
|
raise ClassiqExpansionError(
|
67
67
|
f"{self.quantum_type.type_name} is not subscriptable"
|
68
68
|
)
|
69
|
-
if TYPE_CHECKING:
|
70
|
-
assert self.quantum_type.length is not None
|
71
69
|
if isinstance(start, int) and isinstance(end, int) and start >= end:
|
72
70
|
raise ClassiqExpansionError(
|
73
71
|
f"{self.quantum_type.type_name} slice '{self.handle}[{start}:{end}]' "
|
@@ -75,6 +73,7 @@ class QuantumSymbol:
|
|
75
73
|
)
|
76
74
|
if (isinstance(start, int) and start < 0) or (
|
77
75
|
isinstance(end, int)
|
76
|
+
and self.quantum_type.length is not None
|
78
77
|
and self.quantum_type.length.is_constant()
|
79
78
|
and end > self.quantum_type.length_value
|
80
79
|
):
|
@@ -100,19 +99,23 @@ class QuantumSymbol:
|
|
100
99
|
raise ClassiqExpansionError(
|
101
100
|
f"{self.quantum_type.type_name} is not subscriptable"
|
102
101
|
)
|
103
|
-
if TYPE_CHECKING:
|
104
|
-
assert self.quantum_type.length is not None
|
105
102
|
if isinstance(index, int) and (
|
106
103
|
index < 0
|
107
104
|
or (
|
108
|
-
self.quantum_type.length
|
105
|
+
self.quantum_type.length is not None
|
106
|
+
and self.quantum_type.length.is_constant()
|
109
107
|
and index >= self.quantum_type.length_value
|
110
108
|
)
|
111
109
|
):
|
110
|
+
length_suffix = (
|
111
|
+
f" (of length {self.quantum_type.length})"
|
112
|
+
if self.quantum_type.length is not None
|
113
|
+
else ""
|
114
|
+
)
|
112
115
|
raise ClassiqExpansionError(
|
113
116
|
f"Index {index} is out of bounds for "
|
114
|
-
f"{self.quantum_type.type_name.lower()} {str(self.handle)!r}
|
115
|
-
f"
|
117
|
+
f"{self.quantum_type.type_name.lower()} {str(self.handle)!r}"
|
118
|
+
f"{length_suffix}"
|
116
119
|
)
|
117
120
|
return QuantumSymbol(
|
118
121
|
handle=SubscriptHandleBinding(
|
@@ -47,3 +47,21 @@ class BitwiseNot(Function):
|
|
47
47
|
return ~a
|
48
48
|
|
49
49
|
return None
|
50
|
+
|
51
|
+
|
52
|
+
class RShift(Function):
|
53
|
+
@classmethod
|
54
|
+
def eval(cls, a: Any, b: Any) -> Optional[int]:
|
55
|
+
if isinstance(a, Integer) and isinstance(b, Integer):
|
56
|
+
return a >> b
|
57
|
+
|
58
|
+
return None
|
59
|
+
|
60
|
+
|
61
|
+
class LShift(Function):
|
62
|
+
@classmethod
|
63
|
+
def eval(cls, a: Any, b: Any) -> Optional[int]:
|
64
|
+
if isinstance(a, Integer) and isinstance(b, Integer):
|
65
|
+
return a << b
|
66
|
+
|
67
|
+
return None
|
@@ -17,6 +17,9 @@ from sympy.printing.pycode import PythonCodePrinter
|
|
17
17
|
|
18
18
|
from classiq.interface.exceptions import ClassiqInternalExpansionError
|
19
19
|
from classiq.interface.generator.expressions.expression_types import ExpressionValue
|
20
|
+
from classiq.interface.generator.expressions.proxies.classical.any_classical_value import (
|
21
|
+
AnyClassicalValue,
|
22
|
+
)
|
20
23
|
|
21
24
|
from classiq.model_expansions.sympy_conversion.arithmetics import LogicalXor
|
22
25
|
|
@@ -24,7 +27,9 @@ from classiq.model_expansions.sympy_conversion.arithmetics import LogicalXor
|
|
24
27
|
def sympy_to_python(
|
25
28
|
value: Any, locals: Optional[dict[str, ExpressionValue]] = None
|
26
29
|
) -> ExpressionValue:
|
27
|
-
if isinstance(value,
|
30
|
+
if isinstance(value, AnyClassicalValue):
|
31
|
+
pass
|
32
|
+
elif isinstance(value, Integer):
|
28
33
|
value = int(value)
|
29
34
|
elif isinstance(value, Float):
|
30
35
|
value = float(value)
|
@@ -66,6 +71,8 @@ class SympyToQuantumExpressionTranslator(PythonCodePrinter):
|
|
66
71
|
"BitwiseOr": "|",
|
67
72
|
"BitwiseXor": "^",
|
68
73
|
"LogicalXor": "^",
|
74
|
+
"RShift": ">>",
|
75
|
+
"LShift": "<<",
|
69
76
|
}
|
70
77
|
UNARY_BITWISE_OPERATORS_MAPPING = {"BitwiseNot": "~"}
|
71
78
|
|
@@ -117,6 +124,8 @@ class SympyToBoolExpressionTranslator(SympyToQuantumExpressionTranslator):
|
|
117
124
|
|
118
125
|
|
119
126
|
def translate_sympy_quantum_expression(expr: Basic, preserve_bool_ops: bool) -> str:
|
127
|
+
if isinstance(expr, AnyClassicalValue):
|
128
|
+
return str(expr)
|
120
129
|
if preserve_bool_ops:
|
121
130
|
return SympyToBoolExpressionTranslator().doprint(expr)
|
122
131
|
else:
|
@@ -2,8 +2,10 @@ import ast
|
|
2
2
|
import re
|
3
3
|
from collections.abc import Mapping, Sequence
|
4
4
|
from dataclasses import dataclass
|
5
|
+
from functools import cmp_to_key
|
5
6
|
from typing import TypeVar, cast
|
6
7
|
|
8
|
+
from classiq.interface.exceptions import ClassiqInternalExpansionError
|
7
9
|
from classiq.interface.generator.expressions.expression import Expression
|
8
10
|
from classiq.interface.generator.visitor import NodeType
|
9
11
|
from classiq.interface.model.handle_binding import HandleBinding
|
@@ -23,6 +25,39 @@ def _replace_full_word(pattern: str, substitution: str, target: str) -> str:
|
|
23
25
|
)
|
24
26
|
|
25
27
|
|
28
|
+
def _handle_contains_handle(handle: HandleBinding, other_handle: HandleBinding) -> int:
|
29
|
+
if str(other_handle) in str(handle) or other_handle.qmod_expr in handle.qmod_expr:
|
30
|
+
return 1
|
31
|
+
if str(handle) in str(other_handle) or handle.qmod_expr in other_handle.qmod_expr:
|
32
|
+
return -1
|
33
|
+
return 0
|
34
|
+
|
35
|
+
|
36
|
+
class _ExprNormalizer(ast.NodeTransformer):
|
37
|
+
def visit_Call(self, node: ast.Call) -> ast.AST:
|
38
|
+
if not isinstance(node.func, ast.Name):
|
39
|
+
return self.generic_visit(node)
|
40
|
+
if node.func.id == "get_field":
|
41
|
+
if (
|
42
|
+
len(node.args) != 2
|
43
|
+
or not isinstance(node.args[1], ast.Constant)
|
44
|
+
or not isinstance(node.args[1].value, str)
|
45
|
+
):
|
46
|
+
raise ClassiqInternalExpansionError("Unexpected 'get_field' arguments")
|
47
|
+
return ast.Attribute(
|
48
|
+
value=self.visit(node.args[0]), attr=node.args[1].value
|
49
|
+
)
|
50
|
+
if node.func.id == "do_subscript":
|
51
|
+
if len(node.args) != 2:
|
52
|
+
raise ClassiqInternalExpansionError(
|
53
|
+
"Unexpected 'do_subscript' arguments"
|
54
|
+
)
|
55
|
+
return ast.Subscript(
|
56
|
+
value=self.visit(node.args[0]), slice=self.visit(node.args[1])
|
57
|
+
)
|
58
|
+
return self.generic_visit(node)
|
59
|
+
|
60
|
+
|
26
61
|
@dataclass(frozen=True)
|
27
62
|
class HandleRenaming:
|
28
63
|
source_handle: HandleBinding
|
@@ -39,26 +74,29 @@ SymbolRenaming = Mapping[HandleBinding, Sequence[HandleRenaming]]
|
|
39
74
|
def _rewrite_expression(
|
40
75
|
symbol_mapping: SymbolRenaming, expression: Expression
|
41
76
|
) -> Expression:
|
77
|
+
normalized_expr = _ExprNormalizer().visit(ast.parse(expression.expr))
|
42
78
|
vrc = VarRefCollector(
|
43
79
|
ignore_duplicated_handles=True, ignore_sympy_symbols=True, unevaluated=True
|
44
80
|
)
|
45
|
-
vrc.visit(
|
81
|
+
vrc.visit(normalized_expr)
|
46
82
|
|
47
83
|
handle_names = {
|
48
84
|
part.source_handle: part.target_var_handle
|
49
85
|
for parts in symbol_mapping.values()
|
50
86
|
for part in parts
|
51
87
|
}
|
52
|
-
new_expr_str =
|
53
|
-
|
88
|
+
new_expr_str = ast.unparse(normalized_expr)
|
89
|
+
sorted_handles = sorted(
|
90
|
+
vrc.var_handles,
|
91
|
+
key=cmp_to_key( # type:ignore[misc]
|
92
|
+
lambda handle, other_handle: _handle_contains_handle(other_handle, handle)
|
93
|
+
),
|
94
|
+
)
|
95
|
+
for handle in sorted_handles:
|
54
96
|
new_handle = handle.collapse()
|
55
97
|
for handle_to_replace, replacement in handle_names.items():
|
56
98
|
new_handle = new_handle.replace_prefix(handle_to_replace, replacement)
|
57
99
|
new_expr_str = _replace_full_word(str(handle), str(new_handle), new_expr_str)
|
58
|
-
if handle.qmod_expr != str(handle):
|
59
|
-
new_expr_str = _replace_full_word(
|
60
|
-
str(handle.qmod_expr), str(new_handle.qmod_expr), new_expr_str
|
61
|
-
)
|
62
100
|
|
63
101
|
new_expr = Expression(expr=new_expr_str)
|
64
102
|
new_expr._evaluated_expr = expression._evaluated_expr
|
@@ -18,7 +18,7 @@ class _HandlesCollector(Visitor):
|
|
18
18
|
self.handles.append(handle)
|
19
19
|
|
20
20
|
def visit_Expression(self, expression: Expression) -> None:
|
21
|
-
vrc = VarRefCollector(ignore_duplicated_handles=True)
|
21
|
+
vrc = VarRefCollector(ignore_duplicated_handles=True, unevaluated=True)
|
22
22
|
vrc.visit(ast.parse(expression.expr))
|
23
23
|
self.handles.extend(vrc.var_handles)
|
24
24
|
|
@@ -95,16 +95,25 @@ class VarRefCollector(ast.NodeVisitor):
|
|
95
95
|
def visit_Attribute(self, node: ast.Attribute) -> Optional[FieldHandleBinding]:
|
96
96
|
return self._get_field_handle(node.value, node.attr)
|
97
97
|
|
98
|
-
def visit_Call(self, node: ast.Call) -> Optional[
|
99
|
-
if (
|
100
|
-
not isinstance(node.func, ast.Name)
|
101
|
-
or node.func.id != "get_field"
|
102
|
-
or len(node.args) != 2
|
103
|
-
or not isinstance(node.args[1], ast.Constant)
|
104
|
-
or not isinstance(node.args[1].value, str)
|
105
|
-
):
|
98
|
+
def visit_Call(self, node: ast.Call) -> Optional[HandleBinding]:
|
99
|
+
if not isinstance(node.func, ast.Name):
|
106
100
|
return self.generic_visit(node)
|
107
|
-
|
101
|
+
if node.func.id == "get_field":
|
102
|
+
if (
|
103
|
+
len(node.args) != 2
|
104
|
+
or not isinstance(node.args[1], ast.Constant)
|
105
|
+
or not isinstance(node.args[1].value, str)
|
106
|
+
):
|
107
|
+
raise ClassiqInternalExpansionError("Unexpected 'get_field' arguments")
|
108
|
+
return self._get_field_handle(node.args[0], node.args[1].value)
|
109
|
+
if node.func.id == "do_subscript":
|
110
|
+
if len(node.args) != 2:
|
111
|
+
raise ClassiqInternalExpansionError(
|
112
|
+
"Unexpected 'do_subscript' arguments"
|
113
|
+
)
|
114
|
+
self.visit(node.args[1])
|
115
|
+
return self._get_subscript_handle(node.args[0], node.args[1])
|
116
|
+
return self.generic_visit(node)
|
108
117
|
|
109
118
|
def _get_field_handle(
|
110
119
|
self, subject: ast.expr, field: str
|
@@ -121,6 +130,33 @@ class VarRefCollector(ast.NodeVisitor):
|
|
121
130
|
self._var_handles[handle] = True
|
122
131
|
return handle
|
123
132
|
|
133
|
+
def _get_subscript_handle(
|
134
|
+
self, subject: ast.expr, subscript: ast.expr
|
135
|
+
) -> Optional[HandleBinding]:
|
136
|
+
with self.set_nested():
|
137
|
+
base_handle = self.visit(subject)
|
138
|
+
if base_handle is None:
|
139
|
+
return None
|
140
|
+
handle: HandleBinding
|
141
|
+
if isinstance(subscript, ast.Slice):
|
142
|
+
if subscript.lower is None or subscript.upper is None:
|
143
|
+
raise ClassiqExpansionError(
|
144
|
+
f"{str(base_handle)!r} slice must specify both lower and upper bounds"
|
145
|
+
)
|
146
|
+
handle = SlicedHandleBinding(
|
147
|
+
base_handle=base_handle,
|
148
|
+
start=Expression(expr=ast.unparse(subscript.lower)),
|
149
|
+
end=Expression(expr=ast.unparse(subscript.upper)),
|
150
|
+
)
|
151
|
+
else:
|
152
|
+
handle = SubscriptHandleBinding(
|
153
|
+
base_handle=base_handle,
|
154
|
+
index=Expression(expr=ast.unparse(subscript)),
|
155
|
+
)
|
156
|
+
if not self._is_nested:
|
157
|
+
self._var_handles[handle] = True
|
158
|
+
return handle
|
159
|
+
|
124
160
|
def visit_Name(self, node: ast.Name) -> Optional[HandleBinding]:
|
125
161
|
if not self._ignore_sympy_symbols and node.id in set(
|
126
162
|
SYMPY_SUPPORTED_EXPRESSIONS
|
@@ -2,11 +2,11 @@ from typing import Literal
|
|
2
2
|
|
3
3
|
from classiq.qmod.qfunc import qfunc
|
4
4
|
from classiq.qmod.qmod_parameter import CArray, CReal
|
5
|
-
from classiq.qmod.qmod_variable import Input, Output, QArray, QBit
|
5
|
+
from classiq.qmod.qmod_variable import Input, Output, QArray, QBit, QFree
|
6
6
|
|
7
7
|
|
8
8
|
@qfunc(external=True)
|
9
|
-
def free(in_: Input[QArray[QBit]]) -> None:
|
9
|
+
def free(in_: QFree[Input[QArray[QBit]]]) -> None:
|
10
10
|
"""
|
11
11
|
[Qmod core-library function]
|
12
12
|
|
@@ -2,7 +2,7 @@ from typing import Literal
|
|
2
2
|
|
3
3
|
from classiq.qmod.qfunc import qfunc
|
4
4
|
from classiq.qmod.qmod_parameter import CArray, CBool, CReal
|
5
|
-
from classiq.qmod.qmod_variable import Output, QArray, QBit, QNum
|
5
|
+
from classiq.qmod.qmod_variable import Const, Output, QArray, QBit, QFree, QNum
|
6
6
|
|
7
7
|
|
8
8
|
@qfunc(external=True)
|
@@ -24,13 +24,15 @@ def unitary(
|
|
24
24
|
|
25
25
|
@qfunc(external=True)
|
26
26
|
def add(
|
27
|
-
left: QNum,
|
28
|
-
right: QNum,
|
29
|
-
result:
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
27
|
+
left: Const[QNum],
|
28
|
+
right: Const[QNum],
|
29
|
+
result: QFree[
|
30
|
+
Output[
|
31
|
+
QNum[
|
32
|
+
Literal["result_size"],
|
33
|
+
Literal["result_is_signed"],
|
34
|
+
Literal["result_fraction_places"],
|
35
|
+
]
|
34
36
|
]
|
35
37
|
],
|
36
38
|
result_size: CReal,
|
@@ -41,20 +43,20 @@ def add(
|
|
41
43
|
|
42
44
|
|
43
45
|
@qfunc(external=True)
|
44
|
-
def modular_add(left: QArray[QBit], right: QArray[QBit]) -> None:
|
46
|
+
def modular_add(left: Const[QArray[QBit]], right: QFree[QArray[QBit]]) -> None:
|
45
47
|
pass
|
46
48
|
|
47
49
|
|
48
50
|
@qfunc(external=True)
|
49
|
-
def modular_add_constant(left: CReal, right: QNum) -> None:
|
51
|
+
def modular_add_constant(left: CReal, right: QFree[QNum]) -> None:
|
50
52
|
pass
|
51
53
|
|
52
54
|
|
53
55
|
@qfunc(external=True)
|
54
|
-
def integer_xor(left: QArray[QBit], right: QArray[QBit]) -> None:
|
56
|
+
def integer_xor(left: Const[QArray[QBit]], right: QFree[QArray[QBit]]) -> None:
|
55
57
|
pass
|
56
58
|
|
57
59
|
|
58
60
|
@qfunc(external=True)
|
59
|
-
def real_xor_constant(left: CReal, right: QNum) -> None:
|
61
|
+
def real_xor_constant(left: CReal, right: QFree[QNum]) -> None:
|
60
62
|
pass
|
@@ -2,7 +2,7 @@ from typing import Literal
|
|
2
2
|
|
3
3
|
from classiq.qmod.qfunc import qfunc
|
4
4
|
from classiq.qmod.qmod_parameter import CReal
|
5
|
-
from classiq.qmod.qmod_variable import QArray, QBit
|
5
|
+
from classiq.qmod.qmod_variable import Const, QArray, QBit, QFree
|
6
6
|
|
7
7
|
|
8
8
|
@qfunc(external=True)
|
@@ -25,7 +25,7 @@ def H(target: QBit) -> None:
|
|
25
25
|
|
26
26
|
|
27
27
|
@qfunc(external=True)
|
28
|
-
def X(target: QBit) -> None:
|
28
|
+
def X(target: QFree[QBit]) -> None:
|
29
29
|
"""
|
30
30
|
[Qmod core-library function]
|
31
31
|
|
@@ -44,7 +44,7 @@ def X(target: QBit) -> None:
|
|
44
44
|
|
45
45
|
|
46
46
|
@qfunc(external=True)
|
47
|
-
def Y(target: QBit) -> None:
|
47
|
+
def Y(target: QFree[QBit]) -> None:
|
48
48
|
"""
|
49
49
|
[Qmod core-library function]
|
50
50
|
|
@@ -63,7 +63,7 @@ def Y(target: QBit) -> None:
|
|
63
63
|
|
64
64
|
|
65
65
|
@qfunc(external=True)
|
66
|
-
def Z(target: QBit) -> None:
|
66
|
+
def Z(target: Const[QBit]) -> None:
|
67
67
|
"""
|
68
68
|
[Qmod core-library function]
|
69
69
|
|
@@ -82,7 +82,7 @@ def Z(target: QBit) -> None:
|
|
82
82
|
|
83
83
|
|
84
84
|
@qfunc(external=True)
|
85
|
-
def I(target: QBit) -> None:
|
85
|
+
def I(target: Const[QBit]) -> None:
|
86
86
|
"""
|
87
87
|
[Qmod core-library function]
|
88
88
|
|
@@ -101,7 +101,7 @@ def I(target: QBit) -> None:
|
|
101
101
|
|
102
102
|
|
103
103
|
@qfunc(external=True)
|
104
|
-
def S(target: QBit) -> None:
|
104
|
+
def S(target: Const[QBit]) -> None:
|
105
105
|
"""
|
106
106
|
[Qmod core-library function]
|
107
107
|
|
@@ -120,7 +120,7 @@ def S(target: QBit) -> None:
|
|
120
120
|
|
121
121
|
|
122
122
|
@qfunc(external=True)
|
123
|
-
def T(target: QBit) -> None:
|
123
|
+
def T(target: Const[QBit]) -> None:
|
124
124
|
"""
|
125
125
|
[Qmod core-library function]
|
126
126
|
|
@@ -139,7 +139,7 @@ def T(target: QBit) -> None:
|
|
139
139
|
|
140
140
|
|
141
141
|
@qfunc(external=True)
|
142
|
-
def SDG(target: QBit) -> None:
|
142
|
+
def SDG(target: Const[QBit]) -> None:
|
143
143
|
"""
|
144
144
|
[Qmod core-library function]
|
145
145
|
|
@@ -158,7 +158,7 @@ def SDG(target: QBit) -> None:
|
|
158
158
|
|
159
159
|
|
160
160
|
@qfunc(external=True)
|
161
|
-
def TDG(target: QBit) -> None:
|
161
|
+
def TDG(target: Const[QBit]) -> None:
|
162
162
|
"""
|
163
163
|
[Qmod core-library function]
|
164
164
|
|
@@ -177,7 +177,7 @@ def TDG(target: QBit) -> None:
|
|
177
177
|
|
178
178
|
|
179
179
|
@qfunc(external=True)
|
180
|
-
def PHASE(theta: CReal, target: QBit) -> None:
|
180
|
+
def PHASE(theta: CReal, target: Const[QBit]) -> None:
|
181
181
|
"""
|
182
182
|
[Qmod core-library function]
|
183
183
|
|
@@ -239,7 +239,7 @@ def RY(theta: CReal, target: QBit) -> None:
|
|
239
239
|
|
240
240
|
|
241
241
|
@qfunc(external=True)
|
242
|
-
def RZ(theta: CReal, target: QBit) -> None:
|
242
|
+
def RZ(theta: CReal, target: Const[QBit]) -> None:
|
243
243
|
"""
|
244
244
|
[Qmod core-library function]
|
245
245
|
|
@@ -324,7 +324,7 @@ def RYY(theta: CReal, target: QArray[QBit, Literal[2]]) -> None:
|
|
324
324
|
|
325
325
|
|
326
326
|
@qfunc(external=True)
|
327
|
-
def RZZ(theta: CReal, target: QArray[QBit, Literal[2]]) -> None:
|
327
|
+
def RZZ(theta: CReal, target: Const[QArray[QBit, Literal[2]]]) -> None:
|
328
328
|
"""
|
329
329
|
[Qmod core-library function]
|
330
330
|
|
@@ -345,7 +345,7 @@ def RZZ(theta: CReal, target: QArray[QBit, Literal[2]]) -> None:
|
|
345
345
|
|
346
346
|
|
347
347
|
@qfunc(external=True)
|
348
|
-
def CH(ctrl: QBit, target: QBit) -> None:
|
348
|
+
def CH(ctrl: Const[QBit], target: QBit) -> None:
|
349
349
|
"""
|
350
350
|
[Qmod core-library function]
|
351
351
|
|
@@ -370,7 +370,7 @@ def CH(ctrl: QBit, target: QBit) -> None:
|
|
370
370
|
|
371
371
|
|
372
372
|
@qfunc(external=True)
|
373
|
-
def CX(ctrl: QBit, target: QBit) -> None:
|
373
|
+
def CX(ctrl: Const[QBit], target: QFree[QBit]) -> None:
|
374
374
|
"""
|
375
375
|
[Qmod core-library function]
|
376
376
|
|
@@ -395,7 +395,7 @@ def CX(ctrl: QBit, target: QBit) -> None:
|
|
395
395
|
|
396
396
|
|
397
397
|
@qfunc(external=True)
|
398
|
-
def CY(ctrl: QBit, target: QBit) -> None:
|
398
|
+
def CY(ctrl: Const[QBit], target: QFree[QBit]) -> None:
|
399
399
|
"""
|
400
400
|
[Qmod core-library function]
|
401
401
|
|
@@ -420,7 +420,7 @@ def CY(ctrl: QBit, target: QBit) -> None:
|
|
420
420
|
|
421
421
|
|
422
422
|
@qfunc(external=True)
|
423
|
-
def CZ(ctrl: QBit, target: QBit) -> None:
|
423
|
+
def CZ(ctrl: Const[QBit], target: Const[QBit]) -> None:
|
424
424
|
"""
|
425
425
|
[Qmod core-library function]
|
426
426
|
|
@@ -445,7 +445,7 @@ def CZ(ctrl: QBit, target: QBit) -> None:
|
|
445
445
|
|
446
446
|
|
447
447
|
@qfunc(external=True)
|
448
|
-
def CRX(theta: CReal, ctrl: QBit, target: QBit) -> None:
|
448
|
+
def CRX(theta: CReal, ctrl: Const[QBit], target: QBit) -> None:
|
449
449
|
"""
|
450
450
|
[Qmod core-library function]
|
451
451
|
|
@@ -471,7 +471,7 @@ def CRX(theta: CReal, ctrl: QBit, target: QBit) -> None:
|
|
471
471
|
|
472
472
|
|
473
473
|
@qfunc(external=True)
|
474
|
-
def CRY(theta: CReal, ctrl: QBit, target: QBit) -> None:
|
474
|
+
def CRY(theta: CReal, ctrl: Const[QBit], target: QBit) -> None:
|
475
475
|
"""
|
476
476
|
[Qmod core-library function]
|
477
477
|
|
@@ -497,7 +497,7 @@ def CRY(theta: CReal, ctrl: QBit, target: QBit) -> None:
|
|
497
497
|
|
498
498
|
|
499
499
|
@qfunc(external=True)
|
500
|
-
def CRZ(theta: CReal, ctrl: QBit, target: QBit) -> None:
|
500
|
+
def CRZ(theta: CReal, ctrl: Const[QBit], target: Const[QBit]) -> None:
|
501
501
|
"""
|
502
502
|
[Qmod core-library function]
|
503
503
|
|
@@ -523,7 +523,7 @@ def CRZ(theta: CReal, ctrl: QBit, target: QBit) -> None:
|
|
523
523
|
|
524
524
|
|
525
525
|
@qfunc(external=True)
|
526
|
-
def CPHASE(theta: CReal, ctrl: QBit, target: QBit) -> None:
|
526
|
+
def CPHASE(theta: CReal, ctrl: Const[QBit], target: Const[QBit]) -> None:
|
527
527
|
"""
|
528
528
|
[Qmod core-library function]
|
529
529
|
|
@@ -549,7 +549,7 @@ def CPHASE(theta: CReal, ctrl: QBit, target: QBit) -> None:
|
|
549
549
|
|
550
550
|
|
551
551
|
@qfunc(external=True)
|
552
|
-
def SWAP(qbit0: QBit, qbit1: QBit) -> None:
|
552
|
+
def SWAP(qbit0: QFree[QBit], qbit1: QFree[QBit]) -> None:
|
553
553
|
"""
|
554
554
|
[Qmod core-library function]
|
555
555
|
|
@@ -574,7 +574,7 @@ def SWAP(qbit0: QBit, qbit1: QBit) -> None:
|
|
574
574
|
|
575
575
|
|
576
576
|
@qfunc(external=True)
|
577
|
-
def IDENTITY(target: QArray[QBit]) -> None:
|
577
|
+
def IDENTITY(target: Const[QArray[QBit]]) -> None:
|
578
578
|
"""
|
579
579
|
[Qmod core-library function]
|
580
580
|
|
@@ -623,7 +623,7 @@ def U(theta: CReal, phi: CReal, lam: CReal, gam: CReal, target: QBit) -> None:
|
|
623
623
|
|
624
624
|
|
625
625
|
@qfunc(external=True)
|
626
|
-
def CCX(ctrl: QArray[QBit, Literal[2]], target: QBit) -> None:
|
626
|
+
def CCX(ctrl: Const[QArray[QBit, Literal[2]]], target: QFree[QBit]) -> None:
|
627
627
|
"""
|
628
628
|
[Qmod core-library function]
|
629
629
|
|
@@ -19,6 +19,7 @@ from classiq.interface.generator.functions.concrete_types import ConcreteClassic
|
|
19
19
|
from classiq.interface.generator.functions.port_declaration import (
|
20
20
|
PortDeclarationDirection,
|
21
21
|
)
|
22
|
+
from classiq.interface.generator.functions.type_name import TypeName
|
22
23
|
from classiq.interface.generator.functions.type_qualifier import TypeQualifier
|
23
24
|
from classiq.interface.generator.types.enum_declaration import declaration_from_enum
|
24
25
|
from classiq.interface.generator.types.struct_declaration import StructDeclaration
|
@@ -40,6 +41,10 @@ from classiq.qmod.python_classical_type import PythonClassicalType
|
|
40
41
|
from classiq.qmod.qmod_variable import QVar, get_port_from_type_hint
|
41
42
|
from classiq.qmod.quantum_callable import QCallableList
|
42
43
|
from classiq.qmod.semantics.validation.type_hints import validate_annotation
|
44
|
+
from classiq.qmod.semantics.validation.types_validation import (
|
45
|
+
check_duplicate_types,
|
46
|
+
validate_cstruct,
|
47
|
+
)
|
43
48
|
from classiq.qmod.utilities import unmangle_keyword, version_portable_get_args
|
44
49
|
|
45
50
|
if sys.version_info[0:2] >= (3, 9):
|
@@ -61,14 +66,16 @@ class _PythonClassicalType(PythonClassicalType):
|
|
61
66
|
|
62
67
|
enum_decl = declaration_from_enum(py_type)
|
63
68
|
self.qmodule.enum_decls[py_type.__name__] = enum_decl
|
69
|
+
check_duplicate_types([enum_decl])
|
64
70
|
|
65
|
-
def register_struct(self, py_type: type) ->
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
71
|
+
def register_struct(self, py_type: type) -> TypeName:
|
72
|
+
classical_type = super().register_struct(py_type)
|
73
|
+
if self.qmodule is None:
|
74
|
+
return classical_type
|
75
|
+
all_decls = BUILTIN_STRUCT_DECLARATIONS | self.qmodule.type_decls
|
76
|
+
if py_type.__name__ in all_decls:
|
77
|
+
classical_type.set_classical_struct_decl(all_decls[py_type.__name__])
|
78
|
+
return classical_type
|
72
79
|
|
73
80
|
struct_decl = StructDeclaration(
|
74
81
|
name=py_type.__name__,
|
@@ -77,6 +84,11 @@ class _PythonClassicalType(PythonClassicalType):
|
|
77
84
|
},
|
78
85
|
)
|
79
86
|
self.qmodule.type_decls[py_type.__name__] = struct_decl
|
87
|
+
check_duplicate_types([struct_decl])
|
88
|
+
validate_cstruct(struct_decl)
|
89
|
+
|
90
|
+
classical_type.set_classical_struct_decl(struct_decl)
|
91
|
+
return classical_type
|
80
92
|
|
81
93
|
|
82
94
|
def python_type_to_qmod(
|
classiq/qmod/generative.py
CHANGED
@@ -4,6 +4,11 @@ from typing import TYPE_CHECKING, Any, Optional
|
|
4
4
|
|
5
5
|
from classiq.interface.exceptions import ClassiqError
|
6
6
|
from classiq.interface.generator.expressions.expression import Expression
|
7
|
+
from classiq.interface.generator.expressions.proxies.classical.any_classical_value import (
|
8
|
+
AnyClassicalValue,
|
9
|
+
)
|
10
|
+
|
11
|
+
from classiq.qmod.cparam import CParamScalar
|
7
12
|
|
8
13
|
if TYPE_CHECKING:
|
9
14
|
from classiq.model_expansions.interpreters.generative_interpreter import (
|
@@ -41,4 +46,7 @@ def get_frontend_interpreter() -> "GenerativeInterpreter":
|
|
41
46
|
|
42
47
|
|
43
48
|
def interpret_expression(expr: str) -> Any:
|
44
|
-
|
49
|
+
val = get_frontend_interpreter().evaluate(Expression(expr=expr)).value
|
50
|
+
if isinstance(val, AnyClassicalValue):
|
51
|
+
return CParamScalar(str(val))
|
52
|
+
return val
|
@@ -131,6 +131,10 @@ class ASTToQMODCode:
|
|
131
131
|
]
|
132
132
|
)
|
133
133
|
return f"{self.ast_to_code(node.args[0])} {{{initializer_list}}}"
|
134
|
+
elif func == "do_subscript":
|
135
|
+
if len(node.args) != 2:
|
136
|
+
raise AssertionError("Error parsing array access.")
|
137
|
+
return f"{self.ast_to_code(node.args[0])}[{self.ast_to_code(node.args[1])}]"
|
134
138
|
else:
|
135
139
|
return "{}({})".format(
|
136
140
|
func, ", ".join(self._cleaned_ast_to_code(arg) for arg in node.args)
|
@@ -26,6 +26,7 @@ from classiq.interface.generator.types.struct_declaration import StructDeclarati
|
|
26
26
|
from classiq.interface.generator.visitor import NodeType
|
27
27
|
from classiq.interface.model.allocate import Allocate
|
28
28
|
from classiq.interface.model.bind_operation import BindOperation
|
29
|
+
from classiq.interface.model.block import Block
|
29
30
|
from classiq.interface.model.classical_if import ClassicalIf
|
30
31
|
from classiq.interface.model.classical_parameter_declaration import (
|
31
32
|
AnonClassicalParameterDeclaration,
|
@@ -192,7 +193,7 @@ class DSLPrettyPrinter(ModelVisitor):
|
|
192
193
|
def visit_AnonPortDeclaration(self, port_decl: AnonPortDeclaration) -> str:
|
193
194
|
qualifier_str = (
|
194
195
|
f"{port_decl.type_qualifier} "
|
195
|
-
if port_decl.type_qualifier
|
196
|
+
if port_decl.type_qualifier in [TypeQualifier.Const, TypeQualifier.QFree]
|
196
197
|
else ""
|
197
198
|
)
|
198
199
|
dir_str = (
|
@@ -308,8 +309,6 @@ class DSLPrettyPrinter(ModelVisitor):
|
|
308
309
|
|
309
310
|
def visit_ClassicalIf(self, op: ClassicalIf) -> str:
|
310
311
|
classical_if = f"{self._indent}if ({self.visit(op.condition)}) {{\n"
|
311
|
-
if not op.then:
|
312
|
-
raise AssertionError('Expected non empty "then" block')
|
313
312
|
classical_if += self._visit_body(op.then)
|
314
313
|
|
315
314
|
if op.else_:
|
@@ -345,6 +344,12 @@ class DSLPrettyPrinter(ModelVisitor):
|
|
345
344
|
invert_code += f"{self._indent}}}\n"
|
346
345
|
return invert_code
|
347
346
|
|
347
|
+
def visit_Block(self, block: Block) -> str:
|
348
|
+
invert_code = f"{self._indent}block {{\n"
|
349
|
+
invert_code += self._visit_body(block.statements)
|
350
|
+
invert_code += f"{self._indent}}}\n"
|
351
|
+
return invert_code
|
352
|
+
|
348
353
|
def _visit_body(self, body: StatementBlock) -> str:
|
349
354
|
code = ""
|
350
355
|
self._level += 1
|