classiq 0.82.0__py3-none-any.whl → 0.83.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/applications/chemistry/chemistry_model_constructor.py +2 -2
- classiq/applications/combinatorial_optimization/combinatorial_optimization_model_constructor.py +2 -2
- classiq/interface/_version.py +1 -1
- classiq/interface/generator/application_apis/finance_declarations.py +3 -3
- classiq/interface/generator/expressions/atomic_expression_functions.py +6 -2
- classiq/interface/generator/functions/type_modifier.py +41 -0
- classiq/interface/generator/generated_circuit_data.py +5 -8
- classiq/interface/generator/model/model.py +8 -0
- classiq/interface/generator/quantum_program.py +0 -13
- classiq/interface/generator/types/compilation_metadata.py +1 -1
- classiq/interface/helpers/model_normalizer.py +2 -2
- classiq/interface/model/port_declaration.py +27 -3
- classiq/model_expansions/capturing/captured_vars.py +21 -8
- classiq/model_expansions/evaluators/argument_types.py +2 -2
- classiq/model_expansions/quantum_operations/call_emitter.py +16 -16
- classiq/model_expansions/transformers/model_renamer.py +10 -1
- classiq/model_expansions/transformers/{type_qualifier_inference.py → type_modifier_inference.py} +68 -72
- classiq/model_expansions/visitors/symbolic_param_inference.py +8 -4
- classiq/open_library/functions/state_preparation.py +1 -1
- classiq/qmod/__init__.py +2 -2
- classiq/qmod/builtins/functions/allocation.py +2 -2
- classiq/qmod/builtins/functions/arithmetic.py +16 -8
- classiq/qmod/builtins/functions/standard_gates.py +7 -7
- classiq/qmod/declaration_inferrer.py +5 -5
- classiq/qmod/native/pretty_printer.py +5 -5
- classiq/qmod/pretty_print/pretty_printer.py +6 -6
- classiq/qmod/qfunc.py +1 -1
- classiq/qmod/qmod_variable.py +10 -10
- classiq/qmod/semantics/validation/type_hints.py +9 -9
- classiq/synthesis.py +0 -2
- {classiq-0.82.0.dist-info → classiq-0.83.0.dist-info}/METADATA +1 -1
- {classiq-0.82.0.dist-info → classiq-0.83.0.dist-info}/RECORD +33 -33
- classiq/interface/generator/functions/type_qualifier.py +0 -22
- {classiq-0.82.0.dist-info → classiq-0.83.0.dist-info}/WHEEL +0 -0
classiq/model_expansions/transformers/{type_qualifier_inference.py → type_modifier_inference.py}
RENAMED
@@ -12,7 +12,7 @@ from classiq.interface.exceptions import (
|
|
12
12
|
from classiq.interface.generator.functions.port_declaration import (
|
13
13
|
PortDeclarationDirection,
|
14
14
|
)
|
15
|
-
from classiq.interface.generator.functions.
|
15
|
+
from classiq.interface.generator.functions.type_modifier import TypeModifier
|
16
16
|
from classiq.interface.model.allocate import Allocate
|
17
17
|
from classiq.interface.model.bind_operation import BindOperation
|
18
18
|
from classiq.interface.model.control import Control
|
@@ -37,8 +37,8 @@ from classiq.interface.model.within_apply_operation import WithinApply
|
|
37
37
|
from classiq.model_expansions.visitors.variable_references import VarRefCollector
|
38
38
|
|
39
39
|
|
40
|
-
def
|
41
|
-
port_name: str, expected:
|
40
|
+
def _inconsistent_type_modifier_error(
|
41
|
+
port_name: str, expected: TypeModifier, actual: TypeModifier
|
42
42
|
) -> str:
|
43
43
|
return (
|
44
44
|
f"The type modifier of variable '{port_name}' does not conform to the function signature: "
|
@@ -49,11 +49,11 @@ def _inconsistent_type_qualifier_error(
|
|
49
49
|
)
|
50
50
|
|
51
51
|
|
52
|
-
def
|
53
|
-
expected:
|
52
|
+
def _inconsistent_type_modifier_in_binding_error(
|
53
|
+
expected: TypeModifier, known_modifiers: dict[str, TypeModifier]
|
54
54
|
) -> str:
|
55
55
|
actual = ", ".join(
|
56
|
-
f"{name}: {
|
56
|
+
f"{name}: {modifier.name}" for name, modifier in known_modifiers.items()
|
57
57
|
)
|
58
58
|
return (
|
59
59
|
f"The variable binding has inconsistent type modifiers: "
|
@@ -62,10 +62,10 @@ def _inconsistent_type_qualifier_in_binding_error(
|
|
62
62
|
)
|
63
63
|
|
64
64
|
|
65
|
-
class
|
65
|
+
class TypeModifierValidation(ModelVisitor):
|
66
66
|
"""
|
67
67
|
This class assumes that function calls are topologically sorted, so it traverses
|
68
|
-
the list of function calls and infers the type
|
68
|
+
the list of function calls and infers the type modifiers for each function call
|
69
69
|
without going recursively into the function calls.
|
70
70
|
The function definition ports are modified inplace.
|
71
71
|
"""
|
@@ -77,7 +77,7 @@ class TypeQualifierValidation(ModelVisitor):
|
|
77
77
|
self._inferred_ports: dict[str, PortDeclaration] = dict()
|
78
78
|
self._unchecked: set[str] = set()
|
79
79
|
|
80
|
-
self._initialized_vars: dict[str,
|
80
|
+
self._initialized_vars: dict[str, TypeModifier] = dict()
|
81
81
|
self._bound_vars: list[set[str]] = []
|
82
82
|
|
83
83
|
self._conjugation_context: bool = False
|
@@ -91,7 +91,7 @@ class TypeQualifierValidation(ModelVisitor):
|
|
91
91
|
self, ports: Collection[PortDeclaration], unchecked: Collection[str]
|
92
92
|
) -> Iterator[bool]:
|
93
93
|
for port in ports:
|
94
|
-
if port.
|
94
|
+
if port.type_modifier is TypeModifier.Inferred:
|
95
95
|
self._inferred_ports[port.name] = port
|
96
96
|
else:
|
97
97
|
self._signature_ports[port.name] = port
|
@@ -99,7 +99,7 @@ class TypeQualifierValidation(ModelVisitor):
|
|
99
99
|
|
100
100
|
yield len(self._inferred_ports) > 0 or (
|
101
101
|
any(
|
102
|
-
port.
|
102
|
+
port.type_modifier is not TypeModifier.Mutable
|
103
103
|
for port in self._signature_ports.values()
|
104
104
|
)
|
105
105
|
and not self._skip_validation
|
@@ -123,23 +123,23 @@ class TypeQualifierValidation(ModelVisitor):
|
|
123
123
|
unresolved_ports = [
|
124
124
|
port
|
125
125
|
for port in self._inferred_ports.values()
|
126
|
-
if port.
|
126
|
+
if port.type_modifier is TypeModifier.Inferred
|
127
127
|
]
|
128
128
|
if not self._support_unused_ports and len(unresolved_ports) > 0:
|
129
129
|
raise ClassiqInternalExpansionError(
|
130
130
|
f"Unresolved inferred ports detected: {', '.join(port.name for port in unresolved_ports)}. "
|
131
|
-
"All ports must have their type
|
131
|
+
"All ports must have their type modifiers resolved."
|
132
132
|
)
|
133
133
|
for port in unresolved_ports:
|
134
|
-
port.
|
134
|
+
port.type_modifier = TypeModifier.Const
|
135
135
|
|
136
|
-
def
|
137
|
-
if self._conjugation_context and
|
138
|
-
|
136
|
+
def _validate_modifier(self, candidate: str, modifier: TypeModifier) -> None:
|
137
|
+
if self._conjugation_context and modifier is TypeModifier.Permutable:
|
138
|
+
modifier = TypeModifier.Const
|
139
139
|
|
140
140
|
if candidate in self._inferred_ports:
|
141
|
-
self._inferred_ports[candidate].
|
142
|
-
self._inferred_ports[candidate].
|
141
|
+
self._inferred_ports[candidate].type_modifier = TypeModifier.and_(
|
142
|
+
self._inferred_ports[candidate].type_modifier, modifier
|
143
143
|
)
|
144
144
|
return
|
145
145
|
|
@@ -147,34 +147,32 @@ class TypeQualifierValidation(ModelVisitor):
|
|
147
147
|
return
|
148
148
|
|
149
149
|
if candidate in self._signature_ports:
|
150
|
-
self.
|
150
|
+
self._validate_signature_modifier(candidate, modifier)
|
151
151
|
|
152
152
|
elif candidate in self._initialized_vars:
|
153
|
-
self._initialized_vars[candidate] =
|
154
|
-
self._initialized_vars[candidate],
|
153
|
+
self._initialized_vars[candidate] = TypeModifier.and_(
|
154
|
+
self._initialized_vars[candidate], modifier
|
155
155
|
)
|
156
156
|
|
157
|
-
def
|
158
|
-
self, candidate: str,
|
157
|
+
def _validate_signature_modifier(
|
158
|
+
self, candidate: str, modifier: TypeModifier
|
159
159
|
) -> None:
|
160
|
-
|
161
|
-
if
|
162
|
-
signature_qualifier, qualifier
|
163
|
-
):
|
160
|
+
signature_modifier = self._signature_ports[candidate].type_modifier
|
161
|
+
if signature_modifier is not TypeModifier.and_(signature_modifier, modifier):
|
164
162
|
warnings.warn(
|
165
|
-
|
166
|
-
candidate,
|
163
|
+
_inconsistent_type_modifier_error(
|
164
|
+
candidate, signature_modifier, modifier
|
167
165
|
),
|
168
166
|
ClassiqDeprecationWarning,
|
169
167
|
stacklevel=1,
|
170
168
|
)
|
171
169
|
|
172
|
-
def
|
170
|
+
def _add_initialized_modifier(self, var: str, modifier: TypeModifier) -> None:
|
173
171
|
if var in self._inferred_ports or var in self._signature_ports:
|
174
172
|
return
|
175
|
-
if self._conjugation_context and
|
176
|
-
|
177
|
-
self._initialized_vars[var] =
|
173
|
+
if self._conjugation_context and modifier is TypeModifier.Permutable:
|
174
|
+
modifier = TypeModifier.Const
|
175
|
+
self._initialized_vars[var] = modifier
|
178
176
|
|
179
177
|
def run(
|
180
178
|
self,
|
@@ -190,15 +188,15 @@ class TypeQualifierValidation(ModelVisitor):
|
|
190
188
|
def _update_bound_vars(self) -> None:
|
191
189
|
merged_bound_vars = _merge_overlapping(self._bound_vars)
|
192
190
|
for bound_vars in merged_bound_vars:
|
193
|
-
|
191
|
+
reduced_modifier = self._get_reduced_modifier(bound_vars)
|
194
192
|
for var in bound_vars:
|
195
|
-
self.
|
193
|
+
self._validate_modifier(var, reduced_modifier)
|
196
194
|
|
197
195
|
def visit_QuantumFunctionCall(self, call: QuantumFunctionCall) -> None:
|
198
196
|
for handle, port in call.handles_with_params:
|
199
|
-
self.
|
197
|
+
self._validate_modifier(handle.name, port.type_modifier)
|
200
198
|
if port.direction is PortDeclarationDirection.Output:
|
201
|
-
self.
|
199
|
+
self._add_initialized_modifier(handle.name, port.type_modifier)
|
202
200
|
|
203
201
|
if self._has_inputs(call):
|
204
202
|
bound_vars = {
|
@@ -216,8 +214,8 @@ class TypeQualifierValidation(ModelVisitor):
|
|
216
214
|
)
|
217
215
|
|
218
216
|
def visit_Allocate(self, alloc: Allocate) -> None:
|
219
|
-
self.
|
220
|
-
self.
|
217
|
+
self._validate_modifier(alloc.target.name, TypeModifier.Permutable)
|
218
|
+
self._add_initialized_modifier(alloc.target.name, TypeModifier.Permutable)
|
221
219
|
|
222
220
|
def visit_BindOperation(self, bind_op: BindOperation) -> None:
|
223
221
|
var_names = {
|
@@ -226,51 +224,49 @@ class TypeQualifierValidation(ModelVisitor):
|
|
226
224
|
}
|
227
225
|
self._bound_vars.append(var_names)
|
228
226
|
for handle in bind_op.out_handles:
|
229
|
-
self.
|
227
|
+
self._add_initialized_modifier(handle.name, TypeModifier.Inferred)
|
230
228
|
|
231
|
-
def
|
232
|
-
|
233
|
-
name: self._signature_ports[name].
|
229
|
+
def _get_reduced_modifier(self, bound_vars: set[str]) -> TypeModifier:
|
230
|
+
signature_modifiers = {
|
231
|
+
name: self._signature_ports[name].type_modifier
|
234
232
|
for name in bound_vars.intersection(self._signature_ports)
|
235
233
|
}
|
236
|
-
|
237
|
-
name: self._inferred_ports[name].
|
234
|
+
known_inferred_modifiers = {
|
235
|
+
name: self._inferred_ports[name].type_modifier
|
238
236
|
for name in bound_vars.intersection(self._inferred_ports)
|
239
|
-
if self._inferred_ports[name].
|
237
|
+
if self._inferred_ports[name].type_modifier is not TypeModifier.Inferred
|
240
238
|
}
|
241
|
-
|
239
|
+
known_initialized_modifiers = {
|
242
240
|
name: self._initialized_vars[name]
|
243
241
|
for name in bound_vars.intersection(self._initialized_vars)
|
244
|
-
if self._initialized_vars[name] is not
|
242
|
+
if self._initialized_vars[name] is not TypeModifier.Inferred
|
245
243
|
}
|
246
|
-
|
247
|
-
|
248
|
-
| known_inferred_qualifiers
|
249
|
-
| known_initialized_qualifiers
|
244
|
+
known_modifiers = (
|
245
|
+
signature_modifiers | known_inferred_modifiers | known_initialized_modifiers
|
250
246
|
)
|
251
|
-
|
247
|
+
min_modifier = self._get_min_modifier(list(known_modifiers.values()))
|
252
248
|
if not all(
|
253
|
-
|
254
|
-
for
|
249
|
+
type_modifier is min_modifier
|
250
|
+
for type_modifier in signature_modifiers.values()
|
255
251
|
):
|
256
252
|
warnings.warn(
|
257
|
-
|
258
|
-
|
253
|
+
_inconsistent_type_modifier_in_binding_error(
|
254
|
+
min_modifier, known_modifiers
|
259
255
|
),
|
260
256
|
ClassiqDeprecationWarning,
|
261
257
|
stacklevel=1,
|
262
258
|
)
|
263
259
|
|
264
|
-
return
|
260
|
+
return min_modifier
|
265
261
|
|
266
262
|
@staticmethod
|
267
|
-
def
|
268
|
-
if len(
|
269
|
-
return
|
270
|
-
elif len(
|
271
|
-
return
|
263
|
+
def _get_min_modifier(modifiers: list[TypeModifier]) -> TypeModifier:
|
264
|
+
if len(modifiers) == 0:
|
265
|
+
return TypeModifier.Const
|
266
|
+
elif len(modifiers) == 1:
|
267
|
+
return modifiers[0]
|
272
268
|
else:
|
273
|
-
return functools.reduce(
|
269
|
+
return functools.reduce(TypeModifier.and_, modifiers)
|
274
270
|
|
275
271
|
@staticmethod
|
276
272
|
def _extract_expr_vars(expr_op: QuantumExpressionOperation) -> list[str]:
|
@@ -282,27 +278,27 @@ class TypeQualifierValidation(ModelVisitor):
|
|
282
278
|
|
283
279
|
def visit_ArithmeticOperation(self, arith: ArithmeticOperation) -> None:
|
284
280
|
result_var = arith.result_var.name
|
285
|
-
self.
|
281
|
+
self._validate_modifier(result_var, TypeModifier.Permutable)
|
286
282
|
for expr_var in self._extract_expr_vars(arith):
|
287
|
-
self.
|
283
|
+
self._validate_modifier(expr_var, TypeModifier.Const)
|
288
284
|
if not arith.is_inplace:
|
289
|
-
self.
|
285
|
+
self._add_initialized_modifier(result_var, TypeModifier.Permutable)
|
290
286
|
|
291
287
|
def visit_AmplitudeLoadingOperation(
|
292
288
|
self, amp_load: AmplitudeLoadingOperation
|
293
289
|
) -> None:
|
294
290
|
result_var = amp_load.result_var.name
|
295
|
-
self.
|
291
|
+
self._validate_modifier(result_var, TypeModifier.Mutable)
|
296
292
|
for expr_var in self._extract_expr_vars(amp_load):
|
297
|
-
self.
|
293
|
+
self._validate_modifier(expr_var, TypeModifier.Const)
|
298
294
|
|
299
295
|
def visit_PhaseOperation(self, phase_op: PhaseOperation) -> None:
|
300
296
|
for expr_var in self._extract_expr_vars(phase_op):
|
301
|
-
self.
|
297
|
+
self._validate_modifier(expr_var, TypeModifier.Const)
|
302
298
|
|
303
299
|
def visit_Control(self, control: Control) -> None:
|
304
300
|
for control_var in self._extract_expr_vars(control):
|
305
|
-
self.
|
301
|
+
self._validate_modifier(control_var, TypeModifier.Const)
|
306
302
|
self.visit(control.body)
|
307
303
|
if control.else_block is not None:
|
308
304
|
self.visit(control.else_block)
|
@@ -37,6 +37,13 @@ from classiq.interface.model.quantum_lambda_function import (
|
|
37
37
|
from classiq.model_expansions.visitors.variable_references import VarRefCollector
|
38
38
|
|
39
39
|
|
40
|
+
def handle_is_directly_used_var(handle: HandleBinding, scope_vars: set[str]) -> bool:
|
41
|
+
return handle.name in scope_vars and (
|
42
|
+
not isinstance(handle, FieldHandleBinding)
|
43
|
+
or handle.field not in CLASSICAL_ATTRIBUTES
|
44
|
+
)
|
45
|
+
|
46
|
+
|
40
47
|
def set_generative_recursively(classical_type: ClassicalType) -> None:
|
41
48
|
if (
|
42
49
|
isinstance(classical_type, TypeName)
|
@@ -178,10 +185,7 @@ class SymbolicParamInference(ModelVisitor):
|
|
178
185
|
)
|
179
186
|
vrc.visit(ast.parse(expr))
|
180
187
|
for handle in vrc.var_handles:
|
181
|
-
if handle
|
182
|
-
not isinstance(handle, FieldHandleBinding)
|
183
|
-
or handle.field not in CLASSICAL_ATTRIBUTES
|
184
|
-
):
|
188
|
+
if handle_is_directly_used_var(handle, set(self._scope)):
|
185
189
|
set_generative_recursively(self._scope[handle.name])
|
186
190
|
|
187
191
|
def _process_nested_compile_time_expression(self, expr: str) -> None:
|
@@ -458,7 +458,7 @@ def prepare_dicke_state_unary_input(max_k: int, qvar: QArray[QBit]) -> None:
|
|
458
458
|
"""
|
459
459
|
if qvar.len > max(1, max_k):
|
460
460
|
_dicke_split_cycle_shift(max_k, qvar)
|
461
|
-
prepare_dicke_state_unary_input(
|
461
|
+
prepare_dicke_state_unary_input(min(max_k, qvar.len - 2), qvar[1 : qvar.len])
|
462
462
|
|
463
463
|
|
464
464
|
@qfunc
|
classiq/qmod/__init__.py
CHANGED
@@ -6,7 +6,7 @@ from .expression_query import get_expression_numeric_attributes
|
|
6
6
|
from .qfunc import qfunc
|
7
7
|
from .qmod_constant import QConstant
|
8
8
|
from .qmod_parameter import Array, CArray, CBool, CInt, CReal
|
9
|
-
from .qmod_variable import Const, Input, Output, QArray, QBit,
|
9
|
+
from .qmod_variable import Const, Input, Output, Permutable, QArray, QBit, QNum, QStruct
|
10
10
|
from .quantum_callable import QCallable, QCallableList
|
11
11
|
from .write_qmod import write_qmod
|
12
12
|
|
@@ -19,7 +19,7 @@ __all__ = [
|
|
19
19
|
"Input",
|
20
20
|
"Output",
|
21
21
|
"Const",
|
22
|
-
"
|
22
|
+
"Permutable",
|
23
23
|
"QArray",
|
24
24
|
"QBit",
|
25
25
|
"QNum",
|
@@ -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, Permutable, QArray, QBit
|
6
6
|
|
7
7
|
|
8
8
|
@qfunc(external=True)
|
9
|
-
def free(in_:
|
9
|
+
def free(in_: Permutable[Input[QArray[QBit]]]) -> None:
|
10
10
|
"""
|
11
11
|
[Qmod core-library function]
|
12
12
|
|
@@ -2,7 +2,15 @@ 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
|
5
|
+
from classiq.qmod.qmod_variable import (
|
6
|
+
Const,
|
7
|
+
Input,
|
8
|
+
Output,
|
9
|
+
Permutable,
|
10
|
+
QArray,
|
11
|
+
QBit,
|
12
|
+
QNum,
|
13
|
+
)
|
6
14
|
|
7
15
|
|
8
16
|
@qfunc(external=True)
|
@@ -26,7 +34,7 @@ def unitary(
|
|
26
34
|
def add(
|
27
35
|
left: Const[QNum],
|
28
36
|
right: Const[QNum],
|
29
|
-
result:
|
37
|
+
result: Permutable[
|
30
38
|
Output[
|
31
39
|
QNum[
|
32
40
|
Literal["result_size"],
|
@@ -45,8 +53,8 @@ def add(
|
|
45
53
|
@qfunc(external=True)
|
46
54
|
def add_inplace_right(
|
47
55
|
left: Const[QNum],
|
48
|
-
right:
|
49
|
-
result:
|
56
|
+
right: Permutable[Input[QNum]],
|
57
|
+
result: Permutable[
|
50
58
|
Output[
|
51
59
|
QNum[
|
52
60
|
Literal["result_size"],
|
@@ -63,20 +71,20 @@ def add_inplace_right(
|
|
63
71
|
|
64
72
|
|
65
73
|
@qfunc(external=True)
|
66
|
-
def modular_add(left: Const[QArray[QBit]], right:
|
74
|
+
def modular_add(left: Const[QArray[QBit]], right: Permutable[QArray[QBit]]) -> None:
|
67
75
|
pass
|
68
76
|
|
69
77
|
|
70
78
|
@qfunc(external=True)
|
71
|
-
def modular_add_constant(left: CReal, right:
|
79
|
+
def modular_add_constant(left: CReal, right: Permutable[QNum]) -> None:
|
72
80
|
pass
|
73
81
|
|
74
82
|
|
75
83
|
@qfunc(external=True)
|
76
|
-
def integer_xor(left: Const[QArray[QBit]], right:
|
84
|
+
def integer_xor(left: Const[QArray[QBit]], right: Permutable[QArray[QBit]]) -> None:
|
77
85
|
pass
|
78
86
|
|
79
87
|
|
80
88
|
@qfunc(external=True)
|
81
|
-
def real_xor_constant(left: CReal, right:
|
89
|
+
def real_xor_constant(left: CReal, right: Permutable[QNum]) -> None:
|
82
90
|
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 Const, QArray, QBit
|
5
|
+
from classiq.qmod.qmod_variable import Const, Permutable, QArray, QBit
|
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:
|
28
|
+
def X(target: Permutable[QBit]) -> None:
|
29
29
|
"""
|
30
30
|
[Qmod core-library function]
|
31
31
|
|
@@ -44,7 +44,7 @@ def X(target: QFree[QBit]) -> None:
|
|
44
44
|
|
45
45
|
|
46
46
|
@qfunc(external=True)
|
47
|
-
def Y(target:
|
47
|
+
def Y(target: Permutable[QBit]) -> None:
|
48
48
|
"""
|
49
49
|
[Qmod core-library function]
|
50
50
|
|
@@ -370,7 +370,7 @@ def CH(ctrl: Const[QBit], target: QBit) -> None:
|
|
370
370
|
|
371
371
|
|
372
372
|
@qfunc(external=True)
|
373
|
-
def CX(ctrl: Const[QBit], target:
|
373
|
+
def CX(ctrl: Const[QBit], target: Permutable[QBit]) -> None:
|
374
374
|
"""
|
375
375
|
[Qmod core-library function]
|
376
376
|
|
@@ -395,7 +395,7 @@ def CX(ctrl: Const[QBit], target: QFree[QBit]) -> None:
|
|
395
395
|
|
396
396
|
|
397
397
|
@qfunc(external=True)
|
398
|
-
def CY(ctrl: Const[QBit], target:
|
398
|
+
def CY(ctrl: Const[QBit], target: Permutable[QBit]) -> None:
|
399
399
|
"""
|
400
400
|
[Qmod core-library function]
|
401
401
|
|
@@ -549,7 +549,7 @@ def CPHASE(theta: CReal, ctrl: Const[QBit], target: Const[QBit]) -> None:
|
|
549
549
|
|
550
550
|
|
551
551
|
@qfunc(external=True)
|
552
|
-
def SWAP(qbit0:
|
552
|
+
def SWAP(qbit0: Permutable[QBit], qbit1: Permutable[QBit]) -> None:
|
553
553
|
"""
|
554
554
|
[Qmod core-library function]
|
555
555
|
|
@@ -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: Const[QArray[QBit, Literal[2]]], target:
|
626
|
+
def CCX(ctrl: Const[QArray[QBit, Literal[2]]], target: Permutable[QBit]) -> None:
|
627
627
|
"""
|
628
628
|
[Qmod core-library function]
|
629
629
|
|
@@ -19,8 +19,8 @@ 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_modifier import TypeModifier
|
22
23
|
from classiq.interface.generator.functions.type_name import TypeName
|
23
|
-
from classiq.interface.generator.functions.type_qualifier import TypeQualifier
|
24
24
|
from classiq.interface.generator.types.enum_declaration import declaration_from_enum
|
25
25
|
from classiq.interface.generator.types.struct_declaration import StructDeclaration
|
26
26
|
from classiq.interface.model.classical_parameter_declaration import (
|
@@ -100,12 +100,12 @@ def python_type_to_qmod(
|
|
100
100
|
|
101
101
|
|
102
102
|
def _extract_port_decl(name: Optional[str], py_type: Any) -> AnonPortDeclaration:
|
103
|
-
quantum_type, direction,
|
103
|
+
quantum_type, direction, modifier = get_port_from_type_hint(py_type)
|
104
104
|
param = AnonPortDeclaration(
|
105
105
|
name=None,
|
106
106
|
direction=direction,
|
107
107
|
quantum_type=quantum_type,
|
108
|
-
|
108
|
+
type_modifier=modifier,
|
109
109
|
)
|
110
110
|
if name is not None:
|
111
111
|
param = param.rename(name)
|
@@ -163,7 +163,7 @@ def _unpacked_annotated(arg_0: Any, args: Any) -> _AnnotatedAlias:
|
|
163
163
|
|
164
164
|
def _get_param_name(py_type_args: Any) -> Optional[str]:
|
165
165
|
if isinstance(py_type_args[-1], str) and not isinstance(
|
166
|
-
py_type_args[-1], (PortDeclarationDirection,
|
166
|
+
py_type_args[-1], (PortDeclarationDirection, TypeModifier)
|
167
167
|
):
|
168
168
|
return py_type_args[-1]
|
169
169
|
elif py_type_args[-1] is Literal:
|
@@ -176,7 +176,7 @@ def _validate_annotations(py_type_args: Any, py_type: Any) -> None:
|
|
176
176
|
for arg in py_type_args[1:-1]:
|
177
177
|
if (
|
178
178
|
isinstance(arg, str)
|
179
|
-
and not isinstance(arg, (PortDeclarationDirection,
|
179
|
+
and not isinstance(arg, (PortDeclarationDirection, TypeModifier))
|
180
180
|
) or arg is Literal:
|
181
181
|
raise ClassiqValueError(
|
182
182
|
f"Operand parameter declaration must be of the form <param-type> or "
|
@@ -19,8 +19,8 @@ from classiq.interface.generator.functions.concrete_types import (
|
|
19
19
|
from classiq.interface.generator.functions.port_declaration import (
|
20
20
|
PortDeclarationDirection,
|
21
21
|
)
|
22
|
+
from classiq.interface.generator.functions.type_modifier import TypeModifier
|
22
23
|
from classiq.interface.generator.functions.type_name import TypeName
|
23
|
-
from classiq.interface.generator.functions.type_qualifier import TypeQualifier
|
24
24
|
from classiq.interface.generator.types.compilation_metadata import CompilationMetadata
|
25
25
|
from classiq.interface.generator.types.enum_declaration import EnumDeclaration
|
26
26
|
from classiq.interface.generator.types.qstruct_declaration import QStructDeclaration
|
@@ -196,9 +196,9 @@ class DSLPrettyPrinter(ModelVisitor):
|
|
196
196
|
return f"{var_decl.name}: {self.visit(var_decl.quantum_type)}"
|
197
197
|
|
198
198
|
def visit_AnonPortDeclaration(self, port_decl: AnonPortDeclaration) -> str:
|
199
|
-
|
200
|
-
f"{port_decl.
|
201
|
-
if port_decl.
|
199
|
+
modifier_str = (
|
200
|
+
f"{port_decl.type_modifier} "
|
201
|
+
if port_decl.type_modifier in [TypeModifier.Const, TypeModifier.Permutable]
|
202
202
|
else ""
|
203
203
|
)
|
204
204
|
dir_str = (
|
@@ -208,7 +208,7 @@ class DSLPrettyPrinter(ModelVisitor):
|
|
208
208
|
)
|
209
209
|
param_name = f"{port_decl.name}: " if port_decl.name is not None else ""
|
210
210
|
return (
|
211
|
-
f"{
|
211
|
+
f"{modifier_str}{dir_str}{param_name}{self.visit(port_decl.quantum_type)}"
|
212
212
|
)
|
213
213
|
|
214
214
|
def visit_QuantumBit(self, qtype: QuantumBit) -> str:
|
@@ -21,8 +21,8 @@ from classiq.interface.generator.functions.concrete_types import (
|
|
21
21
|
from classiq.interface.generator.functions.port_declaration import (
|
22
22
|
PortDeclarationDirection,
|
23
23
|
)
|
24
|
+
from classiq.interface.generator.functions.type_modifier import TypeModifier
|
24
25
|
from classiq.interface.generator.functions.type_name import TypeName
|
25
|
-
from classiq.interface.generator.functions.type_qualifier import TypeQualifier
|
26
26
|
from classiq.interface.generator.types.compilation_metadata import CompilationMetadata
|
27
27
|
from classiq.interface.generator.types.enum_declaration import EnumDeclaration
|
28
28
|
from classiq.interface.generator.types.qstruct_declaration import QStructDeclaration
|
@@ -210,8 +210,8 @@ class PythonPrettyPrinter(ModelVisitor):
|
|
210
210
|
if len(unchecked) == 0:
|
211
211
|
return no_unchecked_decorator
|
212
212
|
|
213
|
-
|
214
|
-
unchecked_list = f"[{', '.join(
|
213
|
+
unchecked_modifiers = (f'"{modifier}"' for modifier in unchecked)
|
214
|
+
unchecked_list = f"[{', '.join(unchecked_modifiers)}]"
|
215
215
|
return no_unchecked_decorator + f" (unchecked={unchecked_list})"
|
216
216
|
|
217
217
|
def visit_QuantumFunctionDeclaration(
|
@@ -266,9 +266,9 @@ class PythonPrettyPrinter(ModelVisitor):
|
|
266
266
|
if port_decl.direction is not PortDeclarationDirection.Inout:
|
267
267
|
self._imports[port_decl.direction.name] = 1
|
268
268
|
var_type = f"{port_decl.direction.name}[{var_type}]"
|
269
|
-
if port_decl.
|
270
|
-
self._imports[port_decl.
|
271
|
-
var_type = f"{port_decl.
|
269
|
+
if port_decl.type_modifier in [TypeModifier.Const, TypeModifier.Permutable]:
|
270
|
+
self._imports[port_decl.type_modifier.name] = 1
|
271
|
+
var_type = f"{port_decl.type_modifier.name}[{var_type}]"
|
272
272
|
return var_type
|
273
273
|
|
274
274
|
def visit_QuantumBit(self, qtype: QuantumBit) -> str:
|
classiq/qmod/qfunc.py
CHANGED
@@ -107,6 +107,6 @@ def _validate_directives(
|
|
107
107
|
if synthesize_separately:
|
108
108
|
error_msg += "External functions can't be marked as synthesized separately. \n"
|
109
109
|
if unchecked is not None and len(unchecked) > 0:
|
110
|
-
error_msg += "External functions can't have unchecked
|
110
|
+
error_msg += "External functions can't have unchecked modifiers."
|
111
111
|
if error_msg:
|
112
112
|
raise ClassiqInternalError(error_msg)
|
classiq/qmod/qmod_variable.py
CHANGED
@@ -37,8 +37,8 @@ from classiq.interface.generator.expressions.proxies.quantum.qmod_qarray_proxy i
|
|
37
37
|
from classiq.interface.generator.functions.port_declaration import (
|
38
38
|
PortDeclarationDirection,
|
39
39
|
)
|
40
|
+
from classiq.interface.generator.functions.type_modifier import TypeModifier
|
40
41
|
from classiq.interface.generator.functions.type_name import TypeName
|
41
|
-
from classiq.interface.generator.functions.type_qualifier import TypeQualifier
|
42
42
|
from classiq.interface.generator.types.qstruct_declaration import QStructDeclaration
|
43
43
|
from classiq.interface.model.handle_binding import (
|
44
44
|
FieldHandleBinding,
|
@@ -168,11 +168,11 @@ _Q = TypeVar("_Q", bound=QVar)
|
|
168
168
|
Output = Annotated[_Q, PortDeclarationDirection.Output]
|
169
169
|
Input = Annotated[_Q, PortDeclarationDirection.Input]
|
170
170
|
Const = Annotated[
|
171
|
-
_Q,
|
171
|
+
_Q, TypeModifier.Const
|
172
172
|
] # A constant variable, up to a phase dependent on the computational basis state
|
173
|
-
|
174
|
-
_Q,
|
175
|
-
] # A quantum free variable, up to a phase dependent on the computational basis state
|
173
|
+
Permutable = Annotated[
|
174
|
+
_Q, TypeModifier.Permutable
|
175
|
+
] # A permutable ("quantum free") variable, up to a phase dependent on the computational basis state
|
176
176
|
|
177
177
|
|
178
178
|
class QScalar(QVar, SymbolicExpr):
|
@@ -592,21 +592,21 @@ def get_qvar(qtype: QuantumType, origin: HandleBinding) -> "QVar":
|
|
592
592
|
|
593
593
|
def get_port_from_type_hint(
|
594
594
|
py_type: Any,
|
595
|
-
) -> tuple[QuantumType, PortDeclarationDirection,
|
595
|
+
) -> tuple[QuantumType, PortDeclarationDirection, TypeModifier]:
|
596
596
|
direction = PortDeclarationDirection.Inout # default
|
597
|
-
|
597
|
+
modifier = TypeModifier.Mutable # default
|
598
598
|
|
599
599
|
if isinstance(py_type, _AnnotatedAlias):
|
600
600
|
quantum_type = _to_quantum_type(py_type.__origin__)
|
601
601
|
for metadata in py_type.__metadata__:
|
602
602
|
if isinstance(metadata, PortDeclarationDirection):
|
603
603
|
direction = metadata
|
604
|
-
elif isinstance(metadata,
|
605
|
-
|
604
|
+
elif isinstance(metadata, TypeModifier):
|
605
|
+
modifier = metadata
|
606
606
|
else:
|
607
607
|
quantum_type = _to_quantum_type(py_type)
|
608
608
|
|
609
|
-
return quantum_type, direction,
|
609
|
+
return quantum_type, direction, modifier
|
610
610
|
|
611
611
|
|
612
612
|
def _to_quantum_type(py_type: Any) -> QuantumType:
|