classiq 0.65.4__py3-none-any.whl → 0.66.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 +43 -0
- classiq/applications/qnn/qlayer.py +65 -3
- classiq/execution/execution_session.py +0 -2
- classiq/execution/iqcc.py +66 -1
- classiq/interface/_version.py +1 -1
- classiq/interface/ast_node.py +15 -1
- classiq/interface/backend/backend_preferences.py +0 -14
- classiq/interface/debug_info/debug_info.py +2 -0
- classiq/interface/execution/iqcc.py +25 -0
- classiq/interface/generator/expressions/qmod_qarray_proxy.py +1 -13
- classiq/interface/generator/visitor.py +7 -4
- classiq/interface/model/classical_if.py +4 -0
- classiq/interface/model/control.py +4 -0
- classiq/interface/model/invert.py +4 -0
- classiq/interface/model/model.py +3 -1
- classiq/interface/model/model_visitor.py +14 -0
- classiq/interface/model/power.py +4 -0
- classiq/interface/model/quantum_statement.py +3 -3
- classiq/interface/model/repeat.py +4 -0
- classiq/interface/model/within_apply_operation.py +4 -0
- classiq/interface/server/routes.py +6 -0
- classiq/model_expansions/closure.py +0 -11
- classiq/model_expansions/evaluators/quantum_type_utils.py +6 -6
- classiq/model_expansions/expression_evaluator.py +10 -1
- classiq/model_expansions/interpreters/base_interpreter.py +28 -18
- classiq/model_expansions/interpreters/frontend_generative_interpreter.py +58 -1
- classiq/model_expansions/interpreters/generative_interpreter.py +7 -13
- classiq/model_expansions/quantum_operations/allocate.py +69 -0
- classiq/model_expansions/quantum_operations/call_emitter.py +7 -6
- classiq/model_expansions/quantum_operations/declarative_call_emitter.py +4 -4
- classiq/model_expansions/quantum_operations/emitter.py +2 -15
- classiq/model_expansions/quantum_operations/quantum_function_call.py +22 -0
- classiq/model_expansions/quantum_operations/shallow_emitter.py +21 -35
- classiq/model_expansions/scope_initialization.py +49 -34
- classiq/model_expansions/transformers/model_renamer.py +98 -0
- classiq/model_expansions/transformers/var_splitter.py +7 -82
- classiq/open_library/functions/grover.py +5 -5
- classiq/qmod/builtins/__init__.py +1 -1
- classiq/qmod/builtins/functions/__init__.py +0 -2
- classiq/qmod/builtins/functions/allocation.py +1 -26
- classiq/qmod/builtins/operations.py +12 -6
- classiq/qmod/generative.py +6 -4
- classiq/qmod/native/pretty_printer.py +3 -2
- classiq/qmod/pretty_print/pretty_printer.py +3 -1
- classiq/qmod/qmod_variable.py +6 -1
- classiq/qmod/semantics/annotation/call_annotation.py +30 -2
- classiq/qmod/semantics/annotation/qstruct_annotator.py +2 -2
- classiq/qmod/semantics/error_manager.py +20 -6
- classiq/qmod/semantics/static_semantics_visitor.py +3 -40
- classiq/qmod/semantics/validation/constants_validation.py +2 -3
- classiq/qmod/semantics/validation/function_name_collisions_validation.py +6 -9
- classiq/qmod/semantics/validation/main_validation.py +2 -3
- classiq/qmod/semantics/validation/model_validation.py +25 -0
- classiq/qmod/semantics/validation/signature_validation.py +24 -0
- classiq/qmod/semantics/validation/types_validation.py +45 -46
- classiq/qmod/utilities.py +12 -0
- {classiq-0.65.4.dist-info → classiq-0.66.0.dist-info}/METADATA +1 -1
- {classiq-0.65.4.dist-info → classiq-0.66.0.dist-info}/RECORD +59 -55
- classiq/model_expansions/expression_renamer.py +0 -76
- {classiq-0.65.4.dist-info → classiq-0.66.0.dist-info}/WHEEL +0 -0
@@ -1,22 +1,19 @@
|
|
1
1
|
from collections.abc import Sequence
|
2
|
-
from typing import
|
2
|
+
from typing import Any
|
3
3
|
|
4
4
|
from classiq.interface.exceptions import ClassiqError
|
5
5
|
from classiq.interface.generator.constant import Constant
|
6
6
|
from classiq.interface.generator.expressions.expression_constants import (
|
7
7
|
CPARAM_EXECUTION_SUFFIX,
|
8
|
+
RESERVED_EXPRESSIONS,
|
8
9
|
)
|
9
|
-
from classiq.interface.
|
10
|
-
ClassicalParameterDeclaration,
|
11
|
-
)
|
10
|
+
from classiq.interface.generator.functions.concrete_types import ConcreteClassicalType
|
12
11
|
from classiq.interface.model.handle_binding import HandleBinding
|
13
12
|
from classiq.interface.model.model import MAIN_FUNCTION_NAME, Model
|
14
13
|
from classiq.interface.model.native_function_definition import NativeFunctionDefinition
|
15
14
|
from classiq.interface.model.port_declaration import PortDeclaration
|
16
15
|
from classiq.interface.model.quantum_function_declaration import (
|
17
|
-
NamedParamsQuantumFunctionDeclaration,
|
18
16
|
PositionalArg,
|
19
|
-
QuantumFunctionDeclaration,
|
20
17
|
)
|
21
18
|
|
22
19
|
from classiq.model_expansions.closure import FunctionClosure, GenerativeFunctionClosure
|
@@ -26,7 +23,6 @@ from classiq.model_expansions.evaluators.classical_expression import (
|
|
26
23
|
from classiq.model_expansions.evaluators.parameter_types import (
|
27
24
|
evaluate_type_in_quantum_symbol,
|
28
25
|
)
|
29
|
-
from classiq.model_expansions.expression_renamer import ExpressionRenamer
|
30
26
|
from classiq.model_expansions.scope import Evaluated, QuantumSymbol, Scope
|
31
27
|
from classiq.qmod.builtins import BUILTIN_CONSTANTS
|
32
28
|
from classiq.qmod.builtins.enums import BUILTIN_ENUM_DECLARATIONS
|
@@ -39,19 +35,6 @@ from classiq.qmod.model_state_container import QMODULE
|
|
39
35
|
from classiq.qmod.quantum_function import GenerativeQFunc
|
40
36
|
|
41
37
|
|
42
|
-
def get_main_renamer(
|
43
|
-
func_decls: Sequence[QuantumFunctionDeclaration],
|
44
|
-
) -> ExpressionRenamer:
|
45
|
-
for func_decl in func_decls:
|
46
|
-
if func_decl.name == MAIN_FUNCTION_NAME:
|
47
|
-
if TYPE_CHECKING:
|
48
|
-
assert isinstance(func_decl, NamedParamsQuantumFunctionDeclaration)
|
49
|
-
return ExpressionRenamer.from_positional_arg_declarations(
|
50
|
-
func_decl.positional_arg_declarations, CPARAM_EXECUTION_SUFFIX
|
51
|
-
)
|
52
|
-
return ExpressionRenamer(var_mapping={})
|
53
|
-
|
54
|
-
|
55
38
|
def add_constants_to_scope(constants: list[Constant], scope: Scope) -> None:
|
56
39
|
for constant in constants:
|
57
40
|
scope[constant.name] = Evaluated(
|
@@ -122,21 +105,17 @@ def add_entry_point_params_to_scope(
|
|
122
105
|
parameters: Sequence[PositionalArg], main_closure: FunctionClosure
|
123
106
|
) -> None:
|
124
107
|
for parameter in parameters:
|
125
|
-
if isinstance(parameter, PortDeclaration):
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
|
131
|
-
|
108
|
+
if not isinstance(parameter, PortDeclaration):
|
109
|
+
continue
|
110
|
+
main_closure.scope[parameter.name] = Evaluated(
|
111
|
+
value=QuantumSymbol(
|
112
|
+
handle=HandleBinding(name=parameter.name),
|
113
|
+
quantum_type=evaluate_type_in_quantum_symbol(
|
114
|
+
parameter.quantum_type, main_closure.scope, parameter.name
|
132
115
|
),
|
133
|
-
|
134
|
-
|
135
|
-
|
136
|
-
main_closure.scope[parameter.name] = Evaluated(
|
137
|
-
value=parameter.classical_type.as_symbolic(parameter.name),
|
138
|
-
defining_function=main_closure,
|
139
|
-
)
|
116
|
+
),
|
117
|
+
defining_function=main_closure,
|
118
|
+
)
|
140
119
|
|
141
120
|
|
142
121
|
def init_top_level_scope(model: Model, scope: Scope) -> None:
|
@@ -148,3 +127,39 @@ def init_top_level_scope(model: Model, scope: Scope) -> None:
|
|
148
127
|
def init_builtin_types() -> None:
|
149
128
|
QMODULE.enum_decls |= BUILTIN_ENUM_DECLARATIONS
|
150
129
|
QMODULE.type_decls |= BUILTIN_STRUCT_DECLARATIONS
|
130
|
+
|
131
|
+
|
132
|
+
def _rename_exec_param(param_name: str) -> str:
|
133
|
+
if param_name in RESERVED_EXPRESSIONS:
|
134
|
+
return param_name
|
135
|
+
return param_name + CPARAM_EXECUTION_SUFFIX
|
136
|
+
|
137
|
+
|
138
|
+
def _add_exec_param_parts_to_scope(param_val: Any, scope: Scope) -> None:
|
139
|
+
if not isinstance(param_val, list):
|
140
|
+
scope[str(param_val)] = Evaluated(value=param_val)
|
141
|
+
return
|
142
|
+
for param_part in param_val:
|
143
|
+
_add_exec_param_parts_to_scope(param_part, scope)
|
144
|
+
|
145
|
+
|
146
|
+
def init_exec_params(model: Model, scope: Scope) -> dict[str, ConcreteClassicalType]:
|
147
|
+
if model.execution_parameters is not None:
|
148
|
+
exec_params = {
|
149
|
+
param_name: (param_name, param_type)
|
150
|
+
for param_name, param_type in model.execution_parameters.items()
|
151
|
+
}
|
152
|
+
else:
|
153
|
+
exec_params = {
|
154
|
+
param.name: (_rename_exec_param(param.name), param.classical_type)
|
155
|
+
for param in model.function_dict.get(
|
156
|
+
"_dec_main", model.main_func
|
157
|
+
).param_decls
|
158
|
+
}
|
159
|
+
for param_name, (param_rename, param_type) in exec_params.items():
|
160
|
+
param_val = param_type.as_symbolic(param_rename)
|
161
|
+
scope[param_name] = Evaluated(value=param_val)
|
162
|
+
scope[param_rename] = Evaluated(value=param_val)
|
163
|
+
if isinstance(param_val, list):
|
164
|
+
_add_exec_param_parts_to_scope(param_val, scope)
|
165
|
+
return dict(exec_params.values())
|
@@ -0,0 +1,98 @@
|
|
1
|
+
import ast
|
2
|
+
from collections.abc import Mapping, Sequence
|
3
|
+
from dataclasses import dataclass
|
4
|
+
from typing import TypeVar, cast
|
5
|
+
|
6
|
+
from classiq.interface.generator.expressions.expression import Expression
|
7
|
+
from classiq.interface.generator.visitor import NodeType
|
8
|
+
from classiq.interface.model.handle_binding import HandleBinding
|
9
|
+
from classiq.interface.model.model_visitor import ModelTransformer
|
10
|
+
from classiq.interface.model.quantum_expressions.quantum_expression import (
|
11
|
+
QuantumExpressionOperation,
|
12
|
+
)
|
13
|
+
|
14
|
+
from classiq.model_expansions.visitors.variable_references import VarRefCollector
|
15
|
+
|
16
|
+
AST_NODE = TypeVar("AST_NODE", bound=NodeType)
|
17
|
+
|
18
|
+
|
19
|
+
@dataclass(frozen=True)
|
20
|
+
class HandleRenaming:
|
21
|
+
source_handle: HandleBinding
|
22
|
+
target_var_name: str
|
23
|
+
|
24
|
+
@property
|
25
|
+
def target_var_handle(self) -> HandleBinding:
|
26
|
+
return HandleBinding(name=self.target_var_name)
|
27
|
+
|
28
|
+
|
29
|
+
SymbolRenaming = Mapping[HandleBinding, Sequence[HandleRenaming]]
|
30
|
+
|
31
|
+
|
32
|
+
class ModelRenamer:
|
33
|
+
def rewrite(self, subject: AST_NODE, symbol_mapping: SymbolRenaming) -> AST_NODE:
|
34
|
+
if len(symbol_mapping) == 0:
|
35
|
+
return subject
|
36
|
+
handle_replacements = {
|
37
|
+
part.source_handle: part.target_var_handle
|
38
|
+
for parts in symbol_mapping.values()
|
39
|
+
for part in parts
|
40
|
+
}
|
41
|
+
|
42
|
+
class ReplaceSplitVars(ModelTransformer):
|
43
|
+
@staticmethod
|
44
|
+
def visit_HandleBinding(handle: HandleBinding) -> HandleBinding:
|
45
|
+
handle = handle.collapse()
|
46
|
+
for handle_to_replace, replacement in handle_replacements.items():
|
47
|
+
handle = handle.replace_prefix(handle_to_replace, replacement)
|
48
|
+
return handle
|
49
|
+
|
50
|
+
@staticmethod
|
51
|
+
def visit_Expression(expr: Expression) -> Expression:
|
52
|
+
return self._rewrite_expression(symbol_mapping, expr)
|
53
|
+
|
54
|
+
def visit_QuantumExpressionOperation(
|
55
|
+
self, op: QuantumExpressionOperation
|
56
|
+
) -> QuantumExpressionOperation:
|
57
|
+
op = cast(QuantumExpressionOperation, self.generic_visit(op))
|
58
|
+
previous_var_handles = list(op._var_handles)
|
59
|
+
op._var_handles = self.visit(op._var_handles)
|
60
|
+
op._var_types = {
|
61
|
+
new_handle.name: op._var_types.get(
|
62
|
+
new_handle.name, op._var_types[previous_handle.name]
|
63
|
+
)
|
64
|
+
for previous_handle, new_handle in zip(
|
65
|
+
previous_var_handles, op._var_handles
|
66
|
+
)
|
67
|
+
}
|
68
|
+
return op
|
69
|
+
|
70
|
+
return ReplaceSplitVars().visit(subject)
|
71
|
+
|
72
|
+
def _rewrite_expression(
|
73
|
+
self,
|
74
|
+
symbol_mapping: SymbolRenaming,
|
75
|
+
expression: Expression,
|
76
|
+
) -> Expression:
|
77
|
+
vrc = VarRefCollector(ignore_duplicated_handles=True)
|
78
|
+
vrc.visit(ast.parse(expression.expr))
|
79
|
+
|
80
|
+
handle_names = {
|
81
|
+
part.source_handle: part.target_var_handle
|
82
|
+
for parts in symbol_mapping.values()
|
83
|
+
for part in parts
|
84
|
+
}
|
85
|
+
new_expr_str = expression.expr
|
86
|
+
for handle in vrc.var_handles:
|
87
|
+
new_handle = handle.collapse()
|
88
|
+
for handle_to_replace, replacement in handle_names.items():
|
89
|
+
new_handle = new_handle.replace_prefix(handle_to_replace, replacement)
|
90
|
+
new_expr_str = new_expr_str.replace(str(handle), str(new_handle))
|
91
|
+
if handle.qmod_expr != str(handle):
|
92
|
+
new_expr_str = new_expr_str.replace(
|
93
|
+
handle.qmod_expr, new_handle.qmod_expr
|
94
|
+
)
|
95
|
+
|
96
|
+
new_expr = Expression(expr=new_expr_str)
|
97
|
+
new_expr._evaluated_expr = expression._evaluated_expr
|
98
|
+
return new_expr
|
@@ -1,14 +1,13 @@
|
|
1
1
|
import ast
|
2
2
|
from dataclasses import dataclass
|
3
3
|
from itertools import chain
|
4
|
-
from typing import TYPE_CHECKING, Callable, Optional
|
4
|
+
from typing import TYPE_CHECKING, Callable, Optional
|
5
5
|
|
6
6
|
from classiq.interface.exceptions import (
|
7
7
|
ClassiqExpansionError,
|
8
8
|
ClassiqInternalExpansionError,
|
9
9
|
)
|
10
10
|
from classiq.interface.generator.expressions.expression import Expression
|
11
|
-
from classiq.interface.generator.visitor import NodeType, Transformer
|
12
11
|
from classiq.interface.model.bind_operation import BindOperation
|
13
12
|
from classiq.interface.model.handle_binding import (
|
14
13
|
HandleBinding,
|
@@ -16,9 +15,6 @@ from classiq.interface.model.handle_binding import (
|
|
16
15
|
SlicedHandleBinding,
|
17
16
|
SubscriptHandleBinding,
|
18
17
|
)
|
19
|
-
from classiq.interface.model.quantum_expressions.quantum_expression import (
|
20
|
-
QuantumExpressionOperation,
|
21
|
-
)
|
22
18
|
from classiq.interface.model.quantum_type import (
|
23
19
|
QuantumBitvector,
|
24
20
|
QuantumScalar,
|
@@ -29,27 +25,23 @@ from classiq.interface.model.variable_declaration_statement import (
|
|
29
25
|
)
|
30
26
|
|
31
27
|
from classiq.model_expansions.scope import QuantumSymbol, Scope
|
28
|
+
from classiq.model_expansions.transformers.model_renamer import (
|
29
|
+
HandleRenaming,
|
30
|
+
ModelRenamer,
|
31
|
+
)
|
32
32
|
from classiq.model_expansions.visitors.variable_references import VarRefCollector
|
33
33
|
|
34
|
-
AST_NODE = TypeVar("AST_NODE", bound=NodeType)
|
35
|
-
|
36
34
|
|
37
35
|
@dataclass(frozen=True)
|
38
|
-
class SymbolPart:
|
39
|
-
source_handle: HandleBinding
|
40
|
-
target_var_name: str
|
36
|
+
class SymbolPart(HandleRenaming):
|
41
37
|
target_var_type: QuantumType
|
42
38
|
|
43
|
-
@property
|
44
|
-
def target_var_handle(self) -> HandleBinding:
|
45
|
-
return HandleBinding(name=self.target_var_name)
|
46
|
-
|
47
39
|
|
48
40
|
SymbolParts = dict[HandleBinding, list[SymbolPart]]
|
49
41
|
PartNamer = Callable[[str], str]
|
50
42
|
|
51
43
|
|
52
|
-
class VarSplitter:
|
44
|
+
class VarSplitter(ModelRenamer):
|
53
45
|
def __init__(self, scope: Scope):
|
54
46
|
self._scope = scope
|
55
47
|
|
@@ -230,70 +222,3 @@ class VarSplitter:
|
|
230
222
|
)
|
231
223
|
for part in chain.from_iterable(symbol_parts.values())
|
232
224
|
]
|
233
|
-
|
234
|
-
def rewrite(self, subject: AST_NODE, symbol_mapping: SymbolParts) -> AST_NODE:
|
235
|
-
if len(symbol_mapping) == 0:
|
236
|
-
return subject
|
237
|
-
handle_replacements = {
|
238
|
-
part.source_handle: part.target_var_handle
|
239
|
-
for parts in symbol_mapping.values()
|
240
|
-
for part in parts
|
241
|
-
}
|
242
|
-
|
243
|
-
class ReplaceSplitVars(Transformer):
|
244
|
-
@staticmethod
|
245
|
-
def visit_HandleBinding(handle: HandleBinding) -> HandleBinding:
|
246
|
-
handle = handle.collapse()
|
247
|
-
for handle_to_replace, replacement in handle_replacements.items():
|
248
|
-
handle = handle.replace_prefix(handle_to_replace, replacement)
|
249
|
-
return handle
|
250
|
-
|
251
|
-
@staticmethod
|
252
|
-
def visit_Expression(expr: Expression) -> Expression:
|
253
|
-
return self._rewrite_expression(symbol_mapping, expr)
|
254
|
-
|
255
|
-
def visit_QuantumExpressionOperation(
|
256
|
-
self, op: QuantumExpressionOperation
|
257
|
-
) -> QuantumExpressionOperation:
|
258
|
-
op = cast(QuantumExpressionOperation, self.generic_visit(op))
|
259
|
-
previous_var_handles = list(op._var_handles)
|
260
|
-
op._var_handles = self.visit(op._var_handles)
|
261
|
-
op._var_types = {
|
262
|
-
new_handle.name: op._var_types.get(
|
263
|
-
new_handle.name, op._var_types[previous_handle.name]
|
264
|
-
)
|
265
|
-
for previous_handle, new_handle in zip(
|
266
|
-
previous_var_handles, op._var_handles
|
267
|
-
)
|
268
|
-
}
|
269
|
-
return op
|
270
|
-
|
271
|
-
return ReplaceSplitVars().visit(subject)
|
272
|
-
|
273
|
-
def _rewrite_expression(
|
274
|
-
self,
|
275
|
-
symbol_mapping: SymbolParts,
|
276
|
-
expression: Expression,
|
277
|
-
) -> Expression:
|
278
|
-
vrc = VarRefCollector(ignore_duplicated_handles=True)
|
279
|
-
vrc.visit(ast.parse(expression.expr))
|
280
|
-
|
281
|
-
handle_names = {
|
282
|
-
part.source_handle: part.target_var_handle
|
283
|
-
for parts in symbol_mapping.values()
|
284
|
-
for part in parts
|
285
|
-
}
|
286
|
-
new_expr_str = expression.expr
|
287
|
-
for handle in vrc.var_handles:
|
288
|
-
new_handle = handle.collapse()
|
289
|
-
for handle_to_replace, replacement in handle_names.items():
|
290
|
-
new_handle = new_handle.replace_prefix(handle_to_replace, replacement)
|
291
|
-
new_expr_str = new_expr_str.replace(str(handle), str(new_handle))
|
292
|
-
if handle.qmod_expr != str(handle):
|
293
|
-
new_expr_str = new_expr_str.replace(
|
294
|
-
handle.qmod_expr, new_handle.qmod_expr
|
295
|
-
)
|
296
|
-
|
297
|
-
new_expr = Expression(expr=new_expr_str)
|
298
|
-
new_expr._evaluated_expr = expression._evaluated_expr
|
299
|
-
return new_expr
|
@@ -25,14 +25,14 @@ def phase_oracle(
|
|
25
25
|
Creates a phase oracle operator based on a predicate function.
|
26
26
|
|
27
27
|
Applies a predicate function and marks "good" and "bad" states with a phase flip.
|
28
|
-
If the predicate is marked as $\\chi$, and the oracle is marked as $S_\\chi$, then:
|
28
|
+
If the predicate is marked as $\\chi$, and the oracle is marked as $S_{\\chi}$, then:
|
29
29
|
|
30
30
|
|
31
31
|
$$
|
32
|
-
S_\\chi\\lvert x
|
33
|
-
|
34
|
-
-\\lvert x
|
35
|
-
|
32
|
+
S_{\\chi}\\lvert x \\rangle =
|
33
|
+
\\begin{cases}
|
34
|
+
-\\lvert x \\rangle & \\text{if } \\chi(x) = 1 \\\\
|
35
|
+
\\phantom{-} \\lvert x \\rangle & \\text{if } \\chi(x) = 0
|
36
36
|
\\end{cases}
|
37
37
|
$$
|
38
38
|
|
@@ -12,7 +12,7 @@ from .enums import * # noqa: F403
|
|
12
12
|
from .enums import __all__ as _builtin_enums
|
13
13
|
from .functions import * # noqa: F403
|
14
14
|
from .functions import __all__ as _builtin_functions
|
15
|
-
from .operations import * #
|
15
|
+
from .operations import * # noqa: F403
|
16
16
|
from .operations import __all__ as _builtin_operations
|
17
17
|
from .structs import * # noqa: F403
|
18
18
|
from .structs import __all__ as _builtin_structs
|
@@ -58,7 +58,6 @@ CORE_LIB_DECLS = [
|
|
58
58
|
real_xor_constant,
|
59
59
|
U,
|
60
60
|
CCX,
|
61
|
-
allocate,
|
62
61
|
free,
|
63
62
|
randomized_benchmarking,
|
64
63
|
inplace_prepare_state,
|
@@ -103,7 +102,6 @@ __all__ = [ # noqa: RUF022
|
|
103
102
|
"Y",
|
104
103
|
"Z",
|
105
104
|
"add",
|
106
|
-
"allocate",
|
107
105
|
"apply",
|
108
106
|
"bloch_sphere_feature_map",
|
109
107
|
"exponentiation_with_depth_constraint",
|
@@ -1,35 +1,10 @@
|
|
1
1
|
from typing import Literal
|
2
2
|
|
3
3
|
from classiq.qmod.qfunc import qfunc
|
4
|
-
from classiq.qmod.qmod_parameter import CArray,
|
4
|
+
from classiq.qmod.qmod_parameter import CArray, CReal
|
5
5
|
from classiq.qmod.qmod_variable import Input, Output, QArray, QBit
|
6
6
|
|
7
7
|
|
8
|
-
@qfunc(external=True)
|
9
|
-
def allocate(
|
10
|
-
num_qubits: CInt, out: Output[QArray[QBit, Literal["num_qubits"]]]
|
11
|
-
) -> None:
|
12
|
-
"""
|
13
|
-
[Qmod core-library function]
|
14
|
-
|
15
|
-
Allocates the specified number of qubits to a given quantum variable and initializes
|
16
|
-
them in the zero state:
|
17
|
-
|
18
|
-
$$
|
19
|
-
\\left|\\text{out}\\right\\rangle = \\left|0\\right\\rangle^{\\otimes \\text{num_qubits}}
|
20
|
-
$$
|
21
|
-
|
22
|
-
Args:
|
23
|
-
num_qubits: The number of qubits to allocate. Must be a positive integer.
|
24
|
-
out: The quantum variable that will receive the allocated qubits. Must be uninitialized before allocation.
|
25
|
-
|
26
|
-
Notes:
|
27
|
-
1. If the output variable has been declared with a specific number of qubits, the number of qubits allocated must match the declared number.
|
28
|
-
2. The synthesis engine automatically handles the allocation, either by drawing new qubits from the available pool or by reusing existing ones.
|
29
|
-
"""
|
30
|
-
pass
|
31
|
-
|
32
|
-
|
33
8
|
@qfunc(external=True)
|
34
9
|
def free(in_: Input[QArray[QBit]]) -> None:
|
35
10
|
"""
|
@@ -65,15 +65,21 @@ def allocate(out: Output[QVar]) -> None:
|
|
65
65
|
|
66
66
|
def allocate(*args: Any, **kwargs: Any) -> None:
|
67
67
|
"""
|
68
|
-
Initialize a quantum variable
|
68
|
+
Initialize a quantum variable to a new quantum object in the zero state:
|
69
69
|
|
70
|
-
|
71
|
-
|
72
|
-
|
70
|
+
$$
|
71
|
+
\\left|\\text{out}\\right\\rangle = \\left|0\\right\\rangle^{\\otimes \\text{num_qubits}}
|
72
|
+
$$
|
73
|
+
|
74
|
+
If 'num_qubits' is not specified, it will be inferred according to the type of 'out'.
|
73
75
|
|
74
76
|
Args:
|
75
|
-
|
76
|
-
out: The
|
77
|
+
num_qubits: The number of qubits to allocate (positive integer, optional).
|
78
|
+
out: The quantum variable that will receive the allocated qubits. Must be uninitialized before allocation.
|
79
|
+
|
80
|
+
Notes:
|
81
|
+
1. If the output variable has been declared with a specific number of qubits, the number of qubits allocated must match the declared number.
|
82
|
+
2. The synthesis engine automatically handles the allocation, either by drawing new qubits from the available pool or by reusing existing ones.
|
77
83
|
"""
|
78
84
|
assert QCallable.CURRENT_EXPANDABLE is not None
|
79
85
|
source_ref = get_source_ref(sys._getframe(1))
|
classiq/qmod/generative.py
CHANGED
@@ -6,10 +6,12 @@ from classiq.interface.exceptions import ClassiqError
|
|
6
6
|
from classiq.interface.generator.expressions.expression import Expression
|
7
7
|
|
8
8
|
if TYPE_CHECKING:
|
9
|
-
from classiq.model_expansions.interpreters.
|
9
|
+
from classiq.model_expansions.interpreters.generative_interpreter import (
|
10
|
+
GenerativeInterpreter,
|
11
|
+
)
|
10
12
|
|
11
13
|
_GENERATIVE_MODE: bool = False
|
12
|
-
_FRONTEND_INTERPRETER: Optional["
|
14
|
+
_FRONTEND_INTERPRETER: Optional["GenerativeInterpreter"] = None
|
13
15
|
|
14
16
|
|
15
17
|
def is_generative_mode() -> bool:
|
@@ -27,12 +29,12 @@ def generative_mode_context(generative: bool) -> Iterator[None]:
|
|
27
29
|
_GENERATIVE_MODE = previous
|
28
30
|
|
29
31
|
|
30
|
-
def set_frontend_interpreter(interpreter: "
|
32
|
+
def set_frontend_interpreter(interpreter: "GenerativeInterpreter") -> None:
|
31
33
|
global _FRONTEND_INTERPRETER
|
32
34
|
_FRONTEND_INTERPRETER = interpreter
|
33
35
|
|
34
36
|
|
35
|
-
def get_frontend_interpreter() -> "
|
37
|
+
def get_frontend_interpreter() -> "GenerativeInterpreter":
|
36
38
|
if _FRONTEND_INTERPRETER is None:
|
37
39
|
raise ClassiqError("Interpreter was not set")
|
38
40
|
return _FRONTEND_INTERPRETER
|
@@ -21,7 +21,7 @@ from classiq.interface.generator.functions.type_name import TypeName
|
|
21
21
|
from classiq.interface.generator.types.enum_declaration import EnumDeclaration
|
22
22
|
from classiq.interface.generator.types.qstruct_declaration import QStructDeclaration
|
23
23
|
from classiq.interface.generator.types.struct_declaration import StructDeclaration
|
24
|
-
from classiq.interface.generator.visitor import NodeType
|
24
|
+
from classiq.interface.generator.visitor import NodeType
|
25
25
|
from classiq.interface.model.allocate import Allocate
|
26
26
|
from classiq.interface.model.bind_operation import BindOperation
|
27
27
|
from classiq.interface.model.classical_if import ClassicalIf
|
@@ -38,6 +38,7 @@ from classiq.interface.model.handle_binding import (
|
|
38
38
|
from classiq.interface.model.inplace_binary_operation import InplaceBinaryOperation
|
39
39
|
from classiq.interface.model.invert import Invert
|
40
40
|
from classiq.interface.model.model import Model
|
41
|
+
from classiq.interface.model.model_visitor import ModelVisitor
|
41
42
|
from classiq.interface.model.native_function_definition import NativeFunctionDefinition
|
42
43
|
from classiq.interface.model.phase_operation import PhaseOperation
|
43
44
|
from classiq.interface.model.port_declaration import (
|
@@ -85,7 +86,7 @@ from classiq.qmod.semantics.annotation.call_annotation import resolve_function_c
|
|
85
86
|
from classiq.qmod.utilities import DEFAULT_DECIMAL_PRECISION
|
86
87
|
|
87
88
|
|
88
|
-
class DSLPrettyPrinter(
|
89
|
+
class DSLPrettyPrinter(ModelVisitor):
|
89
90
|
def __init__(
|
90
91
|
self,
|
91
92
|
decimal_precision: Optional[int] = DEFAULT_DECIMAL_PRECISION,
|
@@ -41,6 +41,7 @@ from classiq.interface.model.handle_binding import (
|
|
41
41
|
from classiq.interface.model.inplace_binary_operation import InplaceBinaryOperation
|
42
42
|
from classiq.interface.model.invert import Invert
|
43
43
|
from classiq.interface.model.model import Model
|
44
|
+
from classiq.interface.model.model_visitor import ModelVisitor
|
44
45
|
from classiq.interface.model.native_function_definition import NativeFunctionDefinition
|
45
46
|
from classiq.interface.model.phase_operation import PhaseOperation
|
46
47
|
from classiq.interface.model.port_declaration import AnonPortDeclaration
|
@@ -120,7 +121,7 @@ class VariableDeclarationAssignment(Visitor):
|
|
120
121
|
return qtype.name, []
|
121
122
|
|
122
123
|
|
123
|
-
class PythonPrettyPrinter(
|
124
|
+
class PythonPrettyPrinter(ModelVisitor):
|
124
125
|
def __init__(self, decimal_precision: int = DEFAULT_DECIMAL_PRECISION) -> None:
|
125
126
|
self._level = 0
|
126
127
|
self._decimal_precision = decimal_precision
|
@@ -407,6 +408,7 @@ class PythonPrettyPrinter(Visitor):
|
|
407
408
|
return ", ".join(self.visit(arg) for arg in func_call.positional_args)
|
408
409
|
|
409
410
|
def visit_Allocate(self, allocate: Allocate) -> str:
|
411
|
+
self._imports["allocate"] = 1
|
410
412
|
if allocate.size is not None:
|
411
413
|
size = f"{self.visit(allocate.size)}, "
|
412
414
|
else:
|
classiq/qmod/qmod_variable.py
CHANGED
@@ -22,6 +22,7 @@ from typing_extensions import ParamSpec, Self, _AnnotatedAlias
|
|
22
22
|
|
23
23
|
from classiq.interface.exceptions import ClassiqValueError
|
24
24
|
from classiq.interface.generator.expressions.expression import Expression
|
25
|
+
from classiq.interface.generator.expressions.non_symbolic_expr import NonSymbolicExpr
|
25
26
|
from classiq.interface.generator.expressions.qmod_qarray_proxy import (
|
26
27
|
ILLEGAL_SLICE_MSG,
|
27
28
|
ILLEGAL_SLICING_STEP_MSG,
|
@@ -185,6 +186,10 @@ class QVar(Symbolic):
|
|
185
186
|
return interpret_expression(str(self.size))
|
186
187
|
return CParamScalar(f"get_field({self}, 'size')")
|
187
188
|
|
189
|
+
@property
|
190
|
+
def type_name(self) -> str:
|
191
|
+
return self.get_qmod_type().type_name
|
192
|
+
|
188
193
|
|
189
194
|
_Q = TypeVar("_Q", bound=QVar)
|
190
195
|
Output = Annotated[_Q, PortDeclarationDirection.Output]
|
@@ -414,7 +419,7 @@ class QNum(Generic[_P], QScalar):
|
|
414
419
|
return _GenericAlias(cls, args)
|
415
420
|
|
416
421
|
|
417
|
-
class QArray(ArrayBase[_P], QVar):
|
422
|
+
class QArray(ArrayBase[_P], QVar, NonSymbolicExpr):
|
418
423
|
CONSTRUCTOR_DEPTH: int = 3
|
419
424
|
|
420
425
|
# TODO [CAD-18620]: improve type hints
|
@@ -3,8 +3,17 @@ from contextlib import contextmanager
|
|
3
3
|
from typing import Any
|
4
4
|
|
5
5
|
from classiq.interface.exceptions import ClassiqError
|
6
|
-
from classiq.interface.generator.
|
6
|
+
from classiq.interface.generator.expressions.expression import Expression
|
7
|
+
from classiq.interface.generator.functions.classical_type import Integer
|
8
|
+
from classiq.interface.generator.functions.port_declaration import (
|
9
|
+
PortDeclarationDirection,
|
10
|
+
)
|
11
|
+
from classiq.interface.model.classical_parameter_declaration import (
|
12
|
+
ClassicalParameterDeclaration,
|
13
|
+
)
|
14
|
+
from classiq.interface.model.model_visitor import ModelVisitor
|
7
15
|
from classiq.interface.model.native_function_definition import NativeFunctionDefinition
|
16
|
+
from classiq.interface.model.port_declaration import PortDeclaration
|
8
17
|
from classiq.interface.model.quantum_function_call import QuantumFunctionCall
|
9
18
|
from classiq.interface.model.quantum_function_declaration import (
|
10
19
|
AnonQuantumOperandDeclaration,
|
@@ -14,17 +23,36 @@ from classiq.interface.model.quantum_function_declaration import (
|
|
14
23
|
from classiq.interface.model.quantum_lambda_function import (
|
15
24
|
QuantumLambdaFunction,
|
16
25
|
)
|
26
|
+
from classiq.interface.model.quantum_type import QuantumBitvector
|
17
27
|
|
18
28
|
from classiq.qmod.builtins.functions import BUILTIN_FUNCTION_DECLARATIONS
|
19
29
|
from classiq.qmod.semantics.annotation.qstruct_annotator import QStructAnnotator
|
20
30
|
from classiq.qmod.semantics.error_manager import ErrorManager
|
21
31
|
from classiq.qmod.semantics.lambdas import get_renamed_parameters
|
22
32
|
|
33
|
+
ALLOCATE_DECL_FOR_COMPATIBILITY = QuantumFunctionDeclaration(
|
34
|
+
name="allocate",
|
35
|
+
positional_arg_declarations=[
|
36
|
+
ClassicalParameterDeclaration(
|
37
|
+
name="num_qubits",
|
38
|
+
classical_type=Integer(),
|
39
|
+
),
|
40
|
+
PortDeclaration(
|
41
|
+
name="out",
|
42
|
+
quantum_type=QuantumBitvector(length=Expression(expr="num_qubits")),
|
43
|
+
direction=PortDeclarationDirection.Output,
|
44
|
+
),
|
45
|
+
],
|
46
|
+
)
|
47
|
+
|
23
48
|
|
24
49
|
def _annotate_function_call_decl(
|
25
50
|
fc: QuantumFunctionCall,
|
26
51
|
function_dict: Mapping[str, QuantumFunctionDeclaration],
|
27
52
|
) -> None:
|
53
|
+
if fc.function == "allocate": # FIXME: Remove compatibility (CAD-25935)
|
54
|
+
fc.set_func_decl(ALLOCATE_DECL_FOR_COMPATIBILITY)
|
55
|
+
return
|
28
56
|
if fc._func_decl is None:
|
29
57
|
func_decl = function_dict.get(fc.func_name)
|
30
58
|
if func_decl is None:
|
@@ -46,7 +74,7 @@ def _annotate_function_call_decl(
|
|
46
74
|
qlambda.set_op_decl(param)
|
47
75
|
|
48
76
|
|
49
|
-
class _CallLambdaAnnotator(
|
77
|
+
class _CallLambdaAnnotator(ModelVisitor):
|
50
78
|
def __init__(
|
51
79
|
self, quantum_functions: Mapping[str, QuantumFunctionDeclaration]
|
52
80
|
) -> None:
|
@@ -1,10 +1,10 @@
|
|
1
1
|
from classiq.interface.generator.functions.type_name import TypeName
|
2
|
-
from classiq.interface.
|
2
|
+
from classiq.interface.model.model_visitor import ModelVisitor
|
3
3
|
|
4
4
|
from classiq.qmod.model_state_container import QMODULE
|
5
5
|
|
6
6
|
|
7
|
-
class QStructAnnotator(
|
7
|
+
class QStructAnnotator(ModelVisitor):
|
8
8
|
def __init__(self) -> None:
|
9
9
|
self._visited: set[TypeName] = set()
|
10
10
|
|