classiq 0.67.0__py3-none-any.whl → 0.68.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.
Files changed (56) hide show
  1. classiq/_internals/api_wrapper.py +5 -1
  2. classiq/_internals/async_utils.py +1 -1
  3. classiq/_internals/authentication/password_manager.py +1 -1
  4. classiq/_internals/client.py +1 -1
  5. classiq/execution/execution_session.py +7 -3
  6. classiq/executor.py +7 -2
  7. classiq/interface/_version.py +1 -1
  8. classiq/interface/ast_node.py +1 -1
  9. classiq/interface/chemistry/operator.py +1 -1
  10. classiq/interface/debug_info/debug_info.py +15 -0
  11. classiq/interface/generator/arith/arithmetic.py +96 -1
  12. classiq/interface/generator/arith/arithmetic_expression_parser.py +1 -1
  13. classiq/interface/generator/generated_circuit_data.py +4 -2
  14. classiq/interface/generator/quantum_program.py +18 -1
  15. classiq/interface/generator/types/enum_declaration.py +33 -2
  16. classiq/interface/model/classical_if.py +2 -2
  17. classiq/interface/model/control.py +2 -2
  18. classiq/interface/model/invert.py +2 -2
  19. classiq/interface/model/power.py +2 -2
  20. classiq/interface/model/quantum_function_call.py +4 -0
  21. classiq/interface/model/repeat.py +2 -2
  22. classiq/interface/model/statement_block.py +1 -1
  23. classiq/interface/model/within_apply_operation.py +2 -2
  24. classiq/model_expansions/interpreters/generative_interpreter.py +78 -18
  25. classiq/model_expansions/quantum_operations/allocate.py +3 -1
  26. classiq/model_expansions/quantum_operations/assignment_result_processor.py +52 -0
  27. classiq/model_expansions/quantum_operations/bind.py +2 -1
  28. classiq/model_expansions/quantum_operations/block_evaluator.py +76 -0
  29. classiq/model_expansions/quantum_operations/classicalif.py +5 -4
  30. classiq/model_expansions/quantum_operations/composite_emitter.py +27 -0
  31. classiq/model_expansions/quantum_operations/emitter.py +16 -2
  32. classiq/model_expansions/quantum_operations/expression_evaluator.py +33 -0
  33. classiq/model_expansions/quantum_operations/handle_evaluator.py +28 -0
  34. classiq/model_expansions/quantum_operations/quantum_function_call.py +3 -2
  35. classiq/model_expansions/quantum_operations/repeat.py +2 -1
  36. classiq/model_expansions/quantum_operations/variable_decleration.py +2 -1
  37. classiq/model_expansions/sympy_conversion/expression_to_sympy.py +1 -1
  38. classiq/open_library/functions/__init__.py +1 -2
  39. classiq/open_library/functions/amplitude_amplification.py +8 -5
  40. classiq/open_library/functions/discrete_sine_cosine_transform.py +16 -13
  41. classiq/open_library/functions/grover.py +6 -10
  42. classiq/open_library/functions/modular_exponentiation.py +7 -13
  43. classiq/open_library/functions/state_preparation.py +16 -17
  44. classiq/open_library/functions/swap_test.py +1 -1
  45. classiq/open_library/functions/utility_functions.py +10 -2
  46. classiq/qmod/builtins/functions/chemistry.py +6 -38
  47. classiq/qmod/quantum_expandable.py +30 -6
  48. classiq/qmod/semantics/validation/types_validation.py +1 -1
  49. classiq/qmod/symbolic.py +2 -1
  50. classiq/qmod/utilities.py +2 -1
  51. classiq/qmod/write_qmod.py +10 -7
  52. classiq/synthesis.py +20 -7
  53. {classiq-0.67.0.dist-info → classiq-0.68.0.dist-info}/METADATA +1 -1
  54. {classiq-0.67.0.dist-info → classiq-0.68.0.dist-info}/RECORD +55 -51
  55. classiq/model_expansions/quantum_operations/shallow_emitter.py +0 -166
  56. {classiq-0.67.0.dist-info → classiq-0.68.0.dist-info}/WHEEL +0 -0
@@ -21,8 +21,11 @@ from classiq.interface.model.model import Model
21
21
  from classiq.interface.model.native_function_definition import NativeFunctionDefinition
22
22
  from classiq.interface.model.phase_operation import PhaseOperation
23
23
  from classiq.interface.model.power import Power
24
- from classiq.interface.model.quantum_expressions.quantum_expression import (
25
- QuantumAssignmentOperation,
24
+ from classiq.interface.model.quantum_expressions.amplitude_loading_operation import (
25
+ AmplitudeLoadingOperation,
26
+ )
27
+ from classiq.interface.model.quantum_expressions.arithmetic_operation import (
28
+ ArithmeticOperation,
26
29
  )
27
30
  from classiq.interface.model.quantum_function_call import QuantumFunctionCall
28
31
  from classiq.interface.model.quantum_function_declaration import (
@@ -55,7 +58,17 @@ from classiq.model_expansions.quantum_operations import (
55
58
  VariableDeclarationStatementEmitter,
56
59
  )
57
60
  from classiq.model_expansions.quantum_operations.allocate import AllocateEmitter
58
- from classiq.model_expansions.quantum_operations.shallow_emitter import ShallowEmitter
61
+ from classiq.model_expansions.quantum_operations.assignment_result_processor import (
62
+ AssignmentResultProcessor,
63
+ )
64
+ from classiq.model_expansions.quantum_operations.block_evaluator import BlockEvaluator
65
+ from classiq.model_expansions.quantum_operations.composite_emitter import (
66
+ CompositeEmitter,
67
+ )
68
+ from classiq.model_expansions.quantum_operations.expression_evaluator import (
69
+ ExpressionEvaluator,
70
+ )
71
+ from classiq.model_expansions.quantum_operations.handle_evaluator import HandleEvaluator
59
72
  from classiq.model_expansions.scope import Evaluated, Scope
60
73
  from classiq.model_expansions.scope_initialization import (
61
74
  add_constants_to_scope,
@@ -134,15 +147,39 @@ class GenerativeInterpreter(BaseInterpreter):
134
147
  BindEmitter(self).emit(bind)
135
148
 
136
149
  @emit.register
137
- def emit_quantum_assignment_operation(self, op: QuantumAssignmentOperation) -> None:
138
- ShallowEmitter(
139
- self, "assignment_operation", components=["expression", "result_var"]
150
+ def emit_amplitude_loading_operation(self, op: AmplitudeLoadingOperation) -> None:
151
+ CompositeEmitter[AmplitudeLoadingOperation](
152
+ self,
153
+ [
154
+ HandleEvaluator(self, "result_var"),
155
+ ExpressionEvaluator(self, "expression"),
156
+ AssignmentResultProcessor(self),
157
+ ],
158
+ ).emit(op)
159
+
160
+ @emit.register
161
+ def _emit_arithmetic_operation(self, op: ArithmeticOperation) -> None:
162
+ self.emit_arithmetic_operation(op)
163
+
164
+ def emit_arithmetic_operation(self, op: ArithmeticOperation) -> None:
165
+ CompositeEmitter[ArithmeticOperation](
166
+ self,
167
+ [
168
+ HandleEvaluator(self, "result_var"),
169
+ ExpressionEvaluator(self, "expression"),
170
+ AssignmentResultProcessor(self),
171
+ ],
140
172
  ).emit(op)
141
173
 
142
174
  @emit.register
143
175
  def emit_inplace_binary_operation(self, op: InplaceBinaryOperation) -> None:
144
- ShallowEmitter(
145
- self, "inplace_binary_operation", components=["target", "value"]
176
+ CompositeEmitter[InplaceBinaryOperation](
177
+ self,
178
+ [
179
+ HandleEvaluator(self, "target"),
180
+ HandleEvaluator(self, "value"),
181
+ ExpressionEvaluator(self, "value"),
182
+ ],
146
183
  ).emit(op)
147
184
 
148
185
  @emit.register
@@ -157,37 +194,60 @@ class GenerativeInterpreter(BaseInterpreter):
157
194
 
158
195
  @emit.register
159
196
  def emit_within_apply(self, within_apply: WithinApply) -> None:
160
- ShallowEmitter(
197
+ BlockEvaluator(
161
198
  self,
162
199
  WITHIN_APPLY_NAME,
163
- components=["within", "apply", "compute", "action"],
200
+ "within",
201
+ "apply",
202
+ "compute",
203
+ "action",
164
204
  ).emit(within_apply)
165
205
 
166
206
  @emit.register
167
207
  def emit_invert(self, invert: Invert) -> None:
168
- ShallowEmitter(self, INVERT_OPERATOR_NAME, components=["body"]).emit(invert)
208
+ BlockEvaluator(self, INVERT_OPERATOR_NAME, "body").emit(invert)
169
209
 
170
210
  @emit.register
171
211
  def emit_repeat(self, repeat: Repeat) -> None:
172
212
  RepeatEmitter(self).emit(repeat)
173
213
 
174
214
  @emit.register
215
+ def _emit_control(self, control: Control) -> None:
216
+ self.emit_control(control)
217
+
175
218
  def emit_control(self, control: Control) -> None:
176
- ShallowEmitter(
219
+ CompositeEmitter[Control](
177
220
  self,
178
- CONTROL_OPERATOR_NAME,
179
- components=["expression", "body", "else_block"],
221
+ [
222
+ ExpressionEvaluator(self, "expression"),
223
+ BlockEvaluator(
224
+ self,
225
+ CONTROL_OPERATOR_NAME,
226
+ "body",
227
+ "else_block",
228
+ ),
229
+ ],
180
230
  ).emit(control)
181
231
 
182
232
  @emit.register
183
233
  def emit_power(self, power: Power) -> None:
184
- ShallowEmitter(self, CONTROL_OPERATOR_NAME, components=["power", "body"]).emit(
185
- power
186
- )
234
+ CompositeEmitter[Power](
235
+ self,
236
+ [
237
+ ExpressionEvaluator(self, "power"),
238
+ BlockEvaluator(self, CONTROL_OPERATOR_NAME, "body"),
239
+ ],
240
+ ).emit(power)
187
241
 
188
242
  @emit.register
189
243
  def emit_phase(self, phase: PhaseOperation) -> None:
190
- ShallowEmitter(self, "phase", components=["expression", "theta"]).emit(phase)
244
+ CompositeEmitter[PhaseOperation](
245
+ self,
246
+ [
247
+ ExpressionEvaluator(self, "expression"),
248
+ ExpressionEvaluator(self, "theta"),
249
+ ],
250
+ ).emit(phase)
191
251
 
192
252
  def _expand_body(self, operation: Closure) -> None:
193
253
  if isinstance(operation, FunctionClosure) and operation.name == "permute":
@@ -12,7 +12,7 @@ from classiq.model_expansions.scope import QuantumSymbol
12
12
 
13
13
 
14
14
  class AllocateEmitter(Emitter[Allocate]):
15
- def emit(self, allocate: Allocate, /) -> None:
15
+ def emit(self, allocate: Allocate, /) -> bool:
16
16
  target: QuantumSymbol = self._interpreter.evaluate(allocate.target).as_type(
17
17
  QuantumSymbol
18
18
  )
@@ -32,6 +32,7 @@ class AllocateEmitter(Emitter[Allocate]):
32
32
  )
33
33
  self._register_debug_info(allocate)
34
34
  self.emit_statement(allocate)
35
+ return True
35
36
 
36
37
  def _get_var_size(self, target: QuantumSymbol, size: Expression | None) -> int:
37
38
  if size is None:
@@ -70,4 +71,5 @@ class AllocateEmitter(Emitter[Allocate]):
70
71
  level=OperationLevel.QMOD_STATEMENT,
71
72
  is_allocate_or_free=True,
72
73
  port_to_passed_variable_map={"ARG": str(allocate.target)},
74
+ node=allocate._as_back_ref(),
73
75
  )
@@ -0,0 +1,52 @@
1
+ from classiq.interface.generator.arith.arithmetic import compute_arithmetic_result_type
2
+ from classiq.interface.generator.functions.port_declaration import (
3
+ PortDeclarationDirection,
4
+ )
5
+ from classiq.interface.model.quantum_expressions.arithmetic_operation import (
6
+ ArithmeticOperation,
7
+ ArithmeticOperationKind,
8
+ )
9
+ from classiq.interface.model.quantum_expressions.quantum_expression import (
10
+ QuantumAssignmentOperation,
11
+ )
12
+
13
+ from classiq.model_expansions.evaluators.quantum_type_utils import copy_type_information
14
+ from classiq.model_expansions.quantum_operations.emitter import Emitter
15
+ from classiq.model_expansions.scope import QuantumSymbol
16
+ from classiq.model_expansions.transformers.ast_renamer import rename_variables
17
+
18
+
19
+ class AssignmentResultProcessor(Emitter[QuantumAssignmentOperation]):
20
+ def emit(self, op: QuantumAssignmentOperation, /) -> bool:
21
+ if (
22
+ isinstance(op, ArithmeticOperation)
23
+ and op.operation_kind == ArithmeticOperationKind.Assignment
24
+ ):
25
+ direction = PortDeclarationDirection.Output
26
+ self._update_result_type(op)
27
+ else:
28
+ direction = PortDeclarationDirection.Inout
29
+ self._capture_handle(op.result_var, direction)
30
+ return False
31
+
32
+ def _update_result_type(self, op: ArithmeticOperation) -> None:
33
+ expr = self._evaluate_expression(op.expression)
34
+ symbols = self._get_symbols_in_expression(expr)
35
+ expr_str = rename_variables(
36
+ expr.expr,
37
+ {str(symbol.handle): symbol.handle.identifier for symbol in symbols}
38
+ | {symbol.handle.qmod_expr: symbol.handle.identifier for symbol in symbols},
39
+ )
40
+ for symbol in symbols:
41
+ expr_str = expr_str.replace(
42
+ symbol.handle.qmod_expr, symbol.handle.identifier
43
+ )
44
+ result_type = compute_arithmetic_result_type(
45
+ expr_str,
46
+ {symbol.handle.identifier: symbol.quantum_type for symbol in symbols},
47
+ self._machine_precision,
48
+ )
49
+ result_symbol = self._interpreter.evaluate(op.result_var).as_type(QuantumSymbol)
50
+ copy_type_information(
51
+ result_type, result_symbol.quantum_type, str(op.result_var)
52
+ )
@@ -16,7 +16,7 @@ from classiq.model_expansions.scope import Evaluated, QuantumSymbol
16
16
 
17
17
 
18
18
  class BindEmitter(Emitter[BindOperation]):
19
- def emit(self, bind: BindOperation, /) -> None:
19
+ def emit(self, bind: BindOperation, /) -> bool:
20
20
  inputs, outputs = self._get_inputs_outputs(bind)
21
21
  validate_bind_targets(bind, self._current_scope)
22
22
  unsized_outputs = [
@@ -56,6 +56,7 @@ class BindEmitter(Emitter[BindOperation]):
56
56
  back_ref=bind.uuid,
57
57
  )
58
58
  )
59
+ return True
59
60
 
60
61
  def _get_inputs_outputs(
61
62
  self, bind: BindOperation
@@ -0,0 +1,76 @@
1
+ from collections.abc import Sequence
2
+ from typing import TYPE_CHECKING
3
+
4
+ from classiq.interface.model.quantum_statement import QuantumOperation, QuantumStatement
5
+
6
+ from classiq.model_expansions.closure import Closure
7
+ from classiq.model_expansions.quantum_operations.emitter import Emitter
8
+ from classiq.model_expansions.scope import Scope
9
+
10
+ if TYPE_CHECKING:
11
+ from classiq.model_expansions.interpreters.base_interpreter import BaseInterpreter
12
+
13
+
14
+ _BLOCK_RENAMES = {
15
+ "compute": "within",
16
+ "action": "apply",
17
+ }
18
+ _REVERSE_BLOCK_RENAMES = {rename: name for name, rename in _BLOCK_RENAMES.items()}
19
+
20
+
21
+ class BlockEvaluator(Emitter[QuantumOperation]):
22
+ def __init__(
23
+ self, interpreter: "BaseInterpreter", operation_name: str, *block_names: str
24
+ ) -> None:
25
+ super().__init__(interpreter)
26
+ self._operation_name = operation_name
27
+ self._block_names: Sequence[str] = block_names
28
+
29
+ def emit(self, op: QuantumOperation, /) -> bool:
30
+ expanded_blocks: dict[str, list[QuantumStatement]] = {}
31
+ blocks = [
32
+ block
33
+ for block in self._block_names
34
+ if hasattr(op, block) and getattr(op, block) is not None
35
+ ]
36
+
37
+ if len(blocks) > 0:
38
+ if op.is_generative():
39
+ expanded_blocks = self.expand_generative_blocks(op)
40
+ else:
41
+ expanded_blocks = self.expand_blocks(op, blocks)
42
+ expanded_blocks.update(expanded_blocks)
43
+
44
+ op = op.model_copy(update={**expanded_blocks, "back_ref": op.uuid})
45
+ self._builder.emit_statement(op)
46
+ return True
47
+
48
+ def expand_blocks(
49
+ self, op: QuantumOperation, block_names: list[str]
50
+ ) -> dict[str, list[QuantumStatement]]:
51
+ blocks = {
52
+ _BLOCK_RENAMES.get(block, block): getattr(op, block)
53
+ for block in block_names
54
+ }
55
+ block_closure = Closure(
56
+ name=self._operation_name,
57
+ scope=Scope(parent=self._current_scope),
58
+ blocks=blocks,
59
+ )
60
+ context = self._expand_operation(block_closure)
61
+ return {
62
+ block: context.statements(_BLOCK_RENAMES.get(block, block))
63
+ for block in block_names
64
+ }
65
+
66
+ def expand_generative_blocks(
67
+ self, op: QuantumOperation
68
+ ) -> dict[str, list[QuantumStatement]]:
69
+ blocks = [
70
+ block for block in self._block_names if op.has_generative_block(block)
71
+ ]
72
+ context = self._expand_generative_context(op, self._operation_name, blocks)
73
+ return {
74
+ _REVERSE_BLOCK_RENAMES.get(block, block): context.statements(block)
75
+ for block in blocks
76
+ }
@@ -18,7 +18,7 @@ def _is_all_identity_calls(body: Sequence[QuantumStatement]) -> bool:
18
18
 
19
19
 
20
20
  class ClassicalIfEmitter(CallEmitter[ClassicalIf]):
21
- def emit(self, classical_if: ClassicalIf, /) -> None:
21
+ def emit(self, classical_if: ClassicalIf, /) -> bool:
22
22
  condition = self._interpreter.evaluate(classical_if.condition).as_type(bool)
23
23
  op_name = "then" if condition else "else"
24
24
  is_generative = classical_if.is_generative()
@@ -26,7 +26,7 @@ class ClassicalIfEmitter(CallEmitter[ClassicalIf]):
26
26
  body: Sequence[QuantumStatement]
27
27
  if is_generative:
28
28
  if not classical_if.has_generative_block(op_name):
29
- return
29
+ return True
30
30
  context = self._expand_generative_context(classical_if, op_name, op_name)
31
31
  context.blocks["body"] = context.blocks[op_name]
32
32
  context.blocks.pop(op_name)
@@ -35,7 +35,7 @@ class ClassicalIfEmitter(CallEmitter[ClassicalIf]):
35
35
  body = classical_if.then if condition else classical_if.else_
36
36
 
37
37
  if _is_all_identity_calls(body):
38
- return
38
+ return True
39
39
 
40
40
  if is_generative or not self._should_wrap(body):
41
41
  for stmt in body:
@@ -43,7 +43,7 @@ class ClassicalIfEmitter(CallEmitter[ClassicalIf]):
43
43
  self._interpreter._builder.emit_statement(stmt)
44
44
  else:
45
45
  self._interpreter.emit_statement(stmt)
46
- return
46
+ return True
47
47
 
48
48
  then_else_func = FunctionClosure.create(
49
49
  name=self._counted_name_allocator.allocate("then" if condition else "else"),
@@ -54,3 +54,4 @@ class ClassicalIfEmitter(CallEmitter[ClassicalIf]):
54
54
  self._emit_quantum_function_call(
55
55
  then_else_func, list(), new_function_debug_info_by_node(classical_if)
56
56
  )
57
+ return True
@@ -0,0 +1,27 @@
1
+ from collections.abc import Sequence
2
+ from typing import TYPE_CHECKING, Generic
3
+
4
+ from classiq.model_expansions.quantum_operations.emitter import (
5
+ Emitter,
6
+ QuantumStatementT,
7
+ )
8
+
9
+ if TYPE_CHECKING:
10
+ from classiq.model_expansions.interpreters.base_interpreter import BaseInterpreter
11
+
12
+
13
+ class CompositeEmitter(Generic[QuantumStatementT], Emitter[QuantumStatementT]):
14
+ def __init__(
15
+ self,
16
+ interpreter: "BaseInterpreter",
17
+ emitters: Sequence[Emitter[QuantumStatementT]],
18
+ ) -> None:
19
+ super().__init__(interpreter)
20
+ self._emitters = emitters
21
+
22
+ def emit(self, statement: QuantumStatementT, /) -> bool:
23
+ for emitter in self._emitters:
24
+ if emitter.emit(statement):
25
+ return True
26
+ self._builder.emit_statement(statement)
27
+ return True
@@ -1,3 +1,4 @@
1
+ import ast
1
2
  from abc import ABC, abstractmethod
2
3
  from typing import (
3
4
  TYPE_CHECKING,
@@ -39,12 +40,15 @@ from classiq.model_expansions.sympy_conversion.sympy_to_python import (
39
40
  translate_sympy_quantum_expression,
40
41
  )
41
42
  from classiq.model_expansions.utils.counted_name_allocator import CountedNameAllocator
43
+ from classiq.model_expansions.visitors.variable_references import VarRefCollector
42
44
  from classiq.qmod.quantum_function import GenerativeQFunc
43
45
 
44
46
  if TYPE_CHECKING:
45
47
  from classiq.model_expansions.interpreters.base_interpreter import BaseInterpreter
46
48
 
47
- QuantumStatementT = TypeVar("QuantumStatementT", bound=QuantumStatement)
49
+ QuantumStatementT = TypeVar(
50
+ "QuantumStatementT", bound=QuantumStatement, contravariant=True
51
+ )
48
52
 
49
53
 
50
54
  class Emitter(Generic[QuantumStatementT], ABC):
@@ -60,7 +64,7 @@ class Emitter(Generic[QuantumStatementT], ABC):
60
64
  )
61
65
 
62
66
  @abstractmethod
63
- def emit(self, statement: QuantumStatementT, /) -> None:
67
+ def emit(self, statement: QuantumStatementT, /) -> bool:
64
68
  pass
65
69
 
66
70
  def _expand_operation(self, closure: Closure) -> OperationContext:
@@ -173,3 +177,13 @@ class Emitter(Generic[QuantumStatementT], ABC):
173
177
  defining_function=defining_function,
174
178
  direction=direction,
175
179
  )
180
+
181
+ def _get_symbols_in_expression(self, expr: Expression) -> list[QuantumSymbol]:
182
+ vrc = VarRefCollector(ignore_duplicated_handles=True)
183
+ vrc.visit(ast.parse(expr.expr))
184
+ handles = dict.fromkeys(
185
+ handle
186
+ for handle in vrc.var_handles
187
+ if isinstance(self._current_scope[handle.name].value, QuantumSymbol)
188
+ )
189
+ return [self._interpreter.evaluate(handle).value for handle in handles]
@@ -0,0 +1,33 @@
1
+ from typing import TYPE_CHECKING
2
+
3
+ from classiq.interface.generator.expressions.expression import Expression
4
+ from classiq.interface.generator.functions.port_declaration import (
5
+ PortDeclarationDirection,
6
+ )
7
+ from classiq.interface.model.quantum_statement import QuantumOperation
8
+
9
+ from classiq.model_expansions.quantum_operations.emitter import Emitter
10
+
11
+ if TYPE_CHECKING:
12
+ from classiq.model_expansions.interpreters.base_interpreter import BaseInterpreter
13
+
14
+
15
+ class ExpressionEvaluator(Emitter[QuantumOperation]):
16
+ def __init__(self, interpreter: "BaseInterpreter", expression_name: str) -> None:
17
+ super().__init__(interpreter)
18
+ self._expression_name = expression_name
19
+
20
+ def emit(self, op: QuantumOperation, /) -> bool:
21
+ expression = getattr(op, self._expression_name)
22
+ if not isinstance(expression, Expression) or expression.is_evaluated():
23
+ return False
24
+ evaluated_expression = self._evaluate_expression(
25
+ expression, preserve_bool_ops=True
26
+ )
27
+ for symbol in self._get_symbols_in_expression(evaluated_expression):
28
+ self._capture_handle(symbol.handle, PortDeclarationDirection.Inout)
29
+ op = op.model_copy(
30
+ update={self._expression_name: evaluated_expression, "back_ref": op.uuid}
31
+ )
32
+ self._interpreter.emit(op)
33
+ return True
@@ -0,0 +1,28 @@
1
+ from typing import TYPE_CHECKING
2
+
3
+ from classiq.interface.model.handle_binding import HandleBinding
4
+ from classiq.interface.model.quantum_statement import QuantumOperation
5
+
6
+ from classiq.model_expansions.quantum_operations.emitter import Emitter
7
+
8
+ if TYPE_CHECKING:
9
+ from classiq.model_expansions.interpreters.base_interpreter import BaseInterpreter
10
+
11
+
12
+ class HandleEvaluator(Emitter[QuantumOperation]):
13
+ def __init__(self, interpreter: "BaseInterpreter", handle_name: str) -> None:
14
+ super().__init__(interpreter)
15
+ self._handle_name = handle_name
16
+
17
+ def emit(self, op: QuantumOperation, /) -> bool:
18
+ handle = getattr(op, self._handle_name)
19
+ if not isinstance(handle, HandleBinding):
20
+ return False
21
+ evaluated_handle = self._interpreter.evaluate(handle).value.handle
22
+ if handle == evaluated_handle:
23
+ return False
24
+ op = op.model_copy(
25
+ update={self._handle_name: evaluated_handle, "back_ref": op.uuid}
26
+ )
27
+ self._interpreter.emit(op)
28
+ return True
@@ -28,16 +28,17 @@ class QuantumFunctionCallEmitter(CallEmitter[QuantumFunctionCall]):
28
28
  super().__init__(interpreter)
29
29
  self._model = self._interpreter._model
30
30
 
31
- def emit(self, call: QuantumFunctionCall, /) -> None:
31
+ def emit(self, call: QuantumFunctionCall, /) -> bool:
32
32
  if call.function == "allocate": # FIXME: Remove compatibility (CAD-25935)
33
33
  self._allocate_compatibility(call)
34
- return
34
+ return True
35
35
  function = self._interpreter.evaluate(call.function).as_type(FunctionClosure)
36
36
  args = call.positional_args
37
37
  with ErrorManager().call(function.name):
38
38
  self._emit_quantum_function_call(
39
39
  function, args, self._debug_info.get(call.uuid)
40
40
  )
41
+ return True
41
42
 
42
43
  def _allocate_compatibility(self, call: QuantumFunctionCall) -> None:
43
44
  if len(call.positional_args) != 2:
@@ -17,7 +17,7 @@ from classiq.qmod.quantum_function import GenerativeQFunc
17
17
 
18
18
 
19
19
  class RepeatEmitter(CallEmitter[Repeat]):
20
- def emit(self, repeat: Repeat, /) -> None:
20
+ def emit(self, repeat: Repeat, /) -> bool:
21
21
  count = self._interpreter.evaluate(repeat.count).as_type(int)
22
22
  if count < 0:
23
23
  raise ClassiqExpansionError(
@@ -26,6 +26,7 @@ class RepeatEmitter(CallEmitter[Repeat]):
26
26
  op_name = self._counted_name_allocator.allocate(REPEAT_OPERATOR_NAME)
27
27
  for i in range(count):
28
28
  self._emit_iteration(repeat, i, op_name)
29
+ return True
29
30
 
30
31
  def _emit_iteration(self, repeat: Repeat, i: int, op_name: str) -> None:
31
32
  closure_constructor: type[FunctionClosure]
@@ -12,7 +12,7 @@ from classiq.model_expansions.scope import Evaluated, QuantumSymbol
12
12
 
13
13
 
14
14
  class VariableDeclarationStatementEmitter(Emitter[VariableDeclarationStatement]):
15
- def emit(self, variable_declaration: VariableDeclarationStatement, /) -> None:
15
+ def emit(self, variable_declaration: VariableDeclarationStatement, /) -> bool:
16
16
  var_decl = variable_declaration.model_copy(
17
17
  update=dict(back_ref=variable_declaration.uuid)
18
18
  )
@@ -36,3 +36,4 @@ class VariableDeclarationStatementEmitter(Emitter[VariableDeclarationStatement])
36
36
  var_decl.name, self._builder.current_function
37
37
  )
38
38
  self.emit_statement(var_decl)
39
+ return True
@@ -174,6 +174,6 @@ class ExpressionSympyTranslator(ast.NodeTransformer):
174
174
  def visit_Attribute(self, node: ast.Attribute) -> ast.Call:
175
175
  return ast.Call(
176
176
  func=ast.Name("get_field"),
177
- args=[node.value, ast.Constant(value=node.attr)],
177
+ args=[self.visit(node.value), ast.Constant(value=node.attr)],
178
178
  keywords=[],
179
179
  )
@@ -10,7 +10,7 @@ from .hea import *
10
10
  from .linear_pauli_rotation import *
11
11
  from .linear_pauli_rotation import _single_pauli
12
12
  from .modular_exponentiation import *
13
- from .modular_exponentiation import _check_msb, _ctrl_x
13
+ from .modular_exponentiation import _check_msb
14
14
  from .qaoa_penalty import *
15
15
  from .qft_functions import *
16
16
  from .qpe import *
@@ -72,7 +72,6 @@ OPEN_LIBRARY_FUNCTIONS = [
72
72
  qst_type2,
73
73
  modular_increment,
74
74
  qft,
75
- _ctrl_x,
76
75
  _prepare_uniform_trimmed_state_step,
77
76
  _qct_d_operator,
78
77
  _qct_pi_operator,
@@ -4,7 +4,7 @@ from classiq.qmod.builtins.operations import (
4
4
  allocate,
5
5
  bind,
6
6
  control,
7
- repeat,
7
+ power,
8
8
  within_apply,
9
9
  )
10
10
  from classiq.qmod.cparam import CInt, CReal
@@ -24,7 +24,7 @@ def amplitude_amplification(
24
24
  """
25
25
  [Qmod Classiq-library function]
26
26
 
27
- Applies the Amplitude Amplification algorithm (QAE); Prepares a state using the given `space_transform` function, and applies `reps` repetititions
27
+ Applies the Amplitude Amplification algorithm; Prepares a state using the given `space_transform` function, and applies `reps` repetititions
28
28
  of the grover operator, using the given `oracle` functions which marks the "good" states.
29
29
 
30
30
  Args:
@@ -34,7 +34,10 @@ def amplitude_amplification(
34
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
35
  """
36
36
  space_transform(packed_qvars)
37
- repeat(reps, lambda index: grover_operator(oracle, space_transform, packed_qvars))
37
+ power(
38
+ reps,
39
+ lambda: grover_operator(oracle, space_transform, packed_qvars),
40
+ )
38
41
 
39
42
 
40
43
  @qfunc
@@ -47,7 +50,7 @@ def exact_amplitude_amplification(
47
50
  """
48
51
  [Qmod Classiq-library function]
49
52
 
50
- Applies an exact version of the Amplitude Amplification algorithm (QAE), assuming knowledge of the amplitude of the marked state.
53
+ Applies an exact version of the Amplitude Amplification algorithm, assuming knowledge of the amplitude of the marked state.
51
54
  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
55
 
53
56
  Based on the algorithm in [Quantum state preparation without coherent arithmetic](https://arxiv.org/abs/2210.14892).
@@ -68,7 +71,7 @@ def exact_amplitude_amplification(
68
71
  theta = pi / (4 * k + 2)
69
72
  rot_phase = 2 * acos(sin(theta) / amplitude)
70
73
 
71
- extended_qvars: QArray = QArray("extended_qvars")
74
+ extended_qvars: QArray = QArray()
72
75
  within_apply(
73
76
  lambda: [ # type:ignore[arg-type]
74
77
  allocate(aux),