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.
Files changed (62) hide show
  1. classiq/_internals/api_wrapper.py +43 -0
  2. classiq/applications/qnn/qlayer.py +65 -3
  3. classiq/execution/execution_session.py +0 -2
  4. classiq/execution/iqcc.py +66 -1
  5. classiq/interface/_version.py +1 -1
  6. classiq/interface/ast_node.py +15 -1
  7. classiq/interface/backend/backend_preferences.py +0 -14
  8. classiq/interface/debug_info/debug_info.py +2 -0
  9. classiq/interface/execution/iqcc.py +25 -0
  10. classiq/interface/generator/expressions/qmod_qarray_proxy.py +1 -13
  11. classiq/interface/generator/visitor.py +7 -4
  12. classiq/interface/model/classical_if.py +4 -0
  13. classiq/interface/model/control.py +4 -0
  14. classiq/interface/model/invert.py +4 -0
  15. classiq/interface/model/model.py +3 -1
  16. classiq/interface/model/model_visitor.py +14 -0
  17. classiq/interface/model/power.py +4 -0
  18. classiq/interface/model/quantum_statement.py +3 -3
  19. classiq/interface/model/repeat.py +4 -0
  20. classiq/interface/model/within_apply_operation.py +4 -0
  21. classiq/interface/server/routes.py +6 -0
  22. classiq/model_expansions/closure.py +0 -11
  23. classiq/model_expansions/evaluators/quantum_type_utils.py +6 -6
  24. classiq/model_expansions/expression_evaluator.py +10 -1
  25. classiq/model_expansions/interpreters/base_interpreter.py +28 -18
  26. classiq/model_expansions/interpreters/frontend_generative_interpreter.py +58 -1
  27. classiq/model_expansions/interpreters/generative_interpreter.py +7 -13
  28. classiq/model_expansions/quantum_operations/allocate.py +69 -0
  29. classiq/model_expansions/quantum_operations/call_emitter.py +7 -6
  30. classiq/model_expansions/quantum_operations/declarative_call_emitter.py +4 -4
  31. classiq/model_expansions/quantum_operations/emitter.py +2 -15
  32. classiq/model_expansions/quantum_operations/quantum_function_call.py +22 -0
  33. classiq/model_expansions/quantum_operations/shallow_emitter.py +21 -35
  34. classiq/model_expansions/scope_initialization.py +49 -34
  35. classiq/model_expansions/transformers/model_renamer.py +98 -0
  36. classiq/model_expansions/transformers/var_splitter.py +7 -82
  37. classiq/open_library/functions/__init__.py +8 -0
  38. classiq/open_library/functions/amplitude_amplification.py +92 -0
  39. classiq/open_library/functions/grover.py +5 -5
  40. classiq/qmod/builtins/__init__.py +1 -1
  41. classiq/qmod/builtins/functions/__init__.py +0 -2
  42. classiq/qmod/builtins/functions/allocation.py +1 -26
  43. classiq/qmod/builtins/operations.py +12 -6
  44. classiq/qmod/generative.py +6 -4
  45. classiq/qmod/native/pretty_printer.py +3 -2
  46. classiq/qmod/pretty_print/pretty_printer.py +3 -1
  47. classiq/qmod/qmod_variable.py +6 -1
  48. classiq/qmod/semantics/annotation/call_annotation.py +30 -2
  49. classiq/qmod/semantics/annotation/qstruct_annotator.py +2 -2
  50. classiq/qmod/semantics/error_manager.py +20 -6
  51. classiq/qmod/semantics/static_semantics_visitor.py +3 -40
  52. classiq/qmod/semantics/validation/constants_validation.py +2 -3
  53. classiq/qmod/semantics/validation/function_name_collisions_validation.py +6 -9
  54. classiq/qmod/semantics/validation/main_validation.py +2 -3
  55. classiq/qmod/semantics/validation/model_validation.py +25 -0
  56. classiq/qmod/semantics/validation/signature_validation.py +24 -0
  57. classiq/qmod/semantics/validation/types_validation.py +45 -46
  58. classiq/qmod/utilities.py +12 -0
  59. {classiq-0.65.4.dist-info → classiq-0.66.1.dist-info}/METADATA +1 -1
  60. {classiq-0.65.4.dist-info → classiq-0.66.1.dist-info}/RECORD +61 -56
  61. classiq/model_expansions/expression_renamer.py +0 -76
  62. {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 TYPE_CHECKING
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.model.classical_parameter_declaration import (
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
- main_closure.scope[parameter.name] = Evaluated(
127
- value=QuantumSymbol(
128
- handle=HandleBinding(name=parameter.name),
129
- quantum_type=evaluate_type_in_quantum_symbol(
130
- parameter.quantum_type, main_closure.scope, parameter.name
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
- defining_function=main_closure,
134
- )
135
- elif isinstance(parameter, ClassicalParameterDeclaration):
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, TypeVar, cast
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 \rangle =
33
- \begin{cases}
34
- -\\lvert x \rangle & \text{if } \\chi(x) = 1 \\
35
- \\phantom{-} \\lvert x \rangle & \text{if } \\chi(x) = 0
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 * # type:ignore[assignment] # noqa: F403
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, CInt, CReal
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
- If 'num_qubits' is specified, 'num_qubits' qubits will be allocated for variable
71
- 'out'. Otherwise, the number of qubits will be inferred according to the type of
72
- 'out'.
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
- size: The number of qubits to be allocated (optional)
76
- out: The target variable
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))
@@ -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.base_interpreter import BaseInterpreter
9
+ from classiq.model_expansions.interpreters.generative_interpreter import (
10
+ GenerativeInterpreter,
11
+ )
10
12
 
11
13
  _GENERATIVE_MODE: bool = False
12
- _FRONTEND_INTERPRETER: Optional["BaseInterpreter"] = None
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: "BaseInterpreter") -> None:
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() -> "BaseInterpreter":
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, Visitor
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(Visitor):
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(Visitor):
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: