classiq 0.65.4__py3-none-any.whl → 0.66.1__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- classiq/_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/__init__.py +8 -0
- classiq/open_library/functions/amplitude_amplification.py +92 -0
- 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.1.dist-info}/METADATA +1 -1
- {classiq-0.65.4.dist-info → classiq-0.66.1.dist-info}/RECORD +61 -56
- classiq/model_expansions/expression_renamer.py +0 -76
- {classiq-0.65.4.dist-info → classiq-0.66.1.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
|
@@ -1,3 +1,7 @@
|
|
1
|
+
from .amplitude_amplification import (
|
2
|
+
amplitude_amplification,
|
3
|
+
exact_amplitude_amplification,
|
4
|
+
)
|
1
5
|
from .amplitude_estimation import *
|
2
6
|
from .discrete_sine_cosine_transform import *
|
3
7
|
from .discrete_sine_cosine_transform import _qct_d_operator, _qct_pi_operator
|
@@ -23,6 +27,8 @@ OPEN_LIBRARY_FUNCTIONS = [
|
|
23
27
|
_single_pauli,
|
24
28
|
linear_pauli_rotations,
|
25
29
|
amplitude_estimation,
|
30
|
+
amplitude_amplification,
|
31
|
+
exact_amplitude_amplification,
|
26
32
|
phase_oracle,
|
27
33
|
reflect_about_zero,
|
28
34
|
grover_diffuser,
|
@@ -78,12 +84,14 @@ OPEN_LIBRARY_FUNCTIONS = [
|
|
78
84
|
__all__ = [
|
79
85
|
"_single_pauli",
|
80
86
|
"allocate_num",
|
87
|
+
"amplitude_amplification",
|
81
88
|
"amplitude_estimation",
|
82
89
|
"apply_to_all",
|
83
90
|
"c_modular_multiply",
|
84
91
|
"cc_modular_add",
|
85
92
|
"encode_in_angle",
|
86
93
|
"encode_on_bloch",
|
94
|
+
"exact_amplitude_amplification",
|
87
95
|
"full_hea",
|
88
96
|
"grover_diffuser",
|
89
97
|
"grover_operator",
|
@@ -0,0 +1,92 @@
|
|
1
|
+
from classiq.open_library.functions.grover import grover_operator
|
2
|
+
from classiq.qmod.builtins.functions.standard_gates import RY
|
3
|
+
from classiq.qmod.builtins.operations import (
|
4
|
+
allocate,
|
5
|
+
bind,
|
6
|
+
control,
|
7
|
+
repeat,
|
8
|
+
within_apply,
|
9
|
+
)
|
10
|
+
from classiq.qmod.cparam import CInt, CReal
|
11
|
+
from classiq.qmod.qfunc import qfunc
|
12
|
+
from classiq.qmod.qmod_variable import QArray, QBit
|
13
|
+
from classiq.qmod.quantum_callable import QCallable
|
14
|
+
from classiq.qmod.symbolic import acos, asin, ceiling, pi, sin
|
15
|
+
|
16
|
+
|
17
|
+
@qfunc
|
18
|
+
def amplitude_amplification(
|
19
|
+
reps: CInt,
|
20
|
+
oracle: QCallable[QArray[QBit]],
|
21
|
+
space_transform: QCallable[QArray[QBit]],
|
22
|
+
packed_qvars: QArray[QBit],
|
23
|
+
) -> None:
|
24
|
+
"""
|
25
|
+
[Qmod Classiq-library function]
|
26
|
+
|
27
|
+
Applies the Amplitude Amplification algorithm (QAE); Prepares a state using the given `space_transform` function, and applies `reps` repetititions
|
28
|
+
of the grover operator, using the given `oracle` functions which marks the "good" states.
|
29
|
+
|
30
|
+
Args:
|
31
|
+
reps: Number of repetitions to apply the grover operator on the initial state. Should be determined by the user, according to the calculated amplification.
|
32
|
+
oracle: The oracle operator that marks the "good" states. This operator should flip the sign of the amplitude of the "good" state.
|
33
|
+
space_transform: The space transform operator (which is known also the state preparation operator). First applied to prepare the state before the amplification, then used inside the Grover operator.
|
34
|
+
packed_vars: The variable that holds the state to be amplified. Assumed to be in the zero state at the beginning of the algorithm.
|
35
|
+
"""
|
36
|
+
space_transform(packed_qvars)
|
37
|
+
repeat(reps, lambda index: grover_operator(oracle, space_transform, packed_qvars))
|
38
|
+
|
39
|
+
|
40
|
+
@qfunc
|
41
|
+
def exact_amplitude_amplification(
|
42
|
+
amplitude: CReal,
|
43
|
+
oracle: QCallable[QArray[QBit]],
|
44
|
+
space_transform: QCallable[QArray[QBit]],
|
45
|
+
packed_qvars: QArray[QBit],
|
46
|
+
) -> None:
|
47
|
+
"""
|
48
|
+
[Qmod Classiq-library function]
|
49
|
+
|
50
|
+
Applies an exact version of the Amplitude Amplification algorithm (QAE), assuming knowledge of the amplitude of the marked state.
|
51
|
+
The function should be applied on the zero state, and it takes care for preparing the initial state before amplification using the `space_transform`.
|
52
|
+
|
53
|
+
Based on the algorithm in [Quantum state preparation without coherent arithmetic](https://arxiv.org/abs/2210.14892).
|
54
|
+
|
55
|
+
Assuming the `space_transform` creates a state $|\\psi\rangle = a|\\psi_good\rangle + \\sqrt(1-a)|\\psi_bad\rangle$, given `a` as the `amplitude`
|
56
|
+
argument, the function will load exactly the state $|\\psi_good\rangle$.
|
57
|
+
|
58
|
+
Note: if the `amplitude` argument is not exact, the resulting state will not be exactly $|\\psi_good\rangle$, and there will be additional internal auxilliary of the function that is not released correctly.
|
59
|
+
|
60
|
+
Args:
|
61
|
+
amplitude: The amplitude of the state $|\\psi_good\rangle$ with regards to the initial state prepared by.
|
62
|
+
oracle: The oracle operator that marks the "good" states. This operator should flip the sign of the amplitude of the "good" state.
|
63
|
+
space_transform: The space transform operator (which is known also the state preparation operator). First applied to prepare the state before the amplification, then used inside the Grover operator.
|
64
|
+
packed_vars: The variable that holds the state to be amplified. Assumed to be in the zero state at the beginning of the algorithm.
|
65
|
+
"""
|
66
|
+
aux = QBit()
|
67
|
+
k = ceiling((pi / (4 * asin(amplitude))) - 0.5)
|
68
|
+
theta = pi / (4 * k + 2)
|
69
|
+
rot_phase = 2 * acos(sin(theta) / amplitude)
|
70
|
+
|
71
|
+
extended_qvars: QArray = QArray("extended_qvars")
|
72
|
+
within_apply(
|
73
|
+
lambda: [ # type:ignore[arg-type]
|
74
|
+
allocate(aux),
|
75
|
+
bind(
|
76
|
+
[aux, packed_qvars], extended_qvars
|
77
|
+
), # type:ignore[func-returns-value]
|
78
|
+
],
|
79
|
+
lambda: amplitude_amplification(
|
80
|
+
k,
|
81
|
+
lambda qvars_: control(
|
82
|
+
qvars_[0] == 0, lambda: oracle(qvars_[1 : qvars_.size])
|
83
|
+
),
|
84
|
+
lambda qvars_: [
|
85
|
+
space_transform( # type:ignore[func-returns-value]
|
86
|
+
qvars_[1 : qvars_.size]
|
87
|
+
),
|
88
|
+
RY(rot_phase, qvars_[0]),
|
89
|
+
],
|
90
|
+
extended_qvars,
|
91
|
+
),
|
92
|
+
)
|
@@ -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:
|